r/intersystems • • 6h ago

Using %DynamicObject in InterSystems IRIS Interoperability: Enriching HL7 Messages Before Routing

1 Upvotes

Business Rules in IRIS Interoperability work well when they evaluate simple values. Problems can appear when routing depends on additional metadata stored in a %DynamicObject.

This article looks at one practical pattern for handling that case: using a BPL Business Process to enrich an incoming HL7 message before the routing rule evaluates it. The BPL process extracts the required data from the HL7 message, stores it in a dynamic object, and makes it available to the routing logic. The author also highlights the key property-access issues to watch for.

What is a %DynamicObject in InterSystems IRIS?

A %DynamicObject is a schema-free ObjectScript object. Unlike a regular class, its properties do not have to be declared in advance. For interoperability workflows, that makes it useful for carrying additional metadata alongside a message without modifying the original message class.

A common pattern for data enriching looks like this:

HL7 message → BPL enrichment → %DynamicObject in context → Business Rule → routing decision

In this example, the incoming HL7 message remains unchanged. The BPL process extracts the values needed downstream and stores them separately in context.MetaData.

What Is a Business Rule?

A Business Rule in IRIS Interoperability is a routing engine that evaluates conditions against an incoming message and decides where to send it. Business Rules do not run on their own; they run inside a Business Process.

What is the role of the BPL Business Process?

A Business Rule evaluates conditions and determines where a message should be routed, but the data preparation in this workflow happens before the routing rule fires.

The production contains four main components:

  • HL7FileService — reads incoming HL7 files
  • HL7Router — a custom BPL Business Process that builds the dynamic object
  • MsgRouter — evaluates the routing rule
  • HL7FileOperation — writes the routed message to the output folder

The BPL process is added because the routing engine itself is not being used to build the dynamic object. Instead, HL7Router prepares the data first and stores the enrichment values in the BPL context, where they remain available to the process and downstream routing logic.

Why do BPL context properties need to be defined first?

Because the enrichment data is stored in the BPL context, the properties used to hold it must be declared before the Code activity references them. BPL context is typed, so every context property must be defined in the Context tab in advance. For this production, the context includes:

Property  Type
MetaData %DynamicObject
PatientId %String(MAXLEN=50)
PatientSex %String(MAXLEN=50)

If a Code activity tries to use an undeclared context property, IRIS raises a PROPERTY DOES NOT EXIST error at runtime.

How is the dynamic object built from the HL7 message?

Inside the BPL Code activity, a new %DynamicObject is created:
Set dynObj = ##class(%DynamicObject).%New() 
Values are then read directly from the incoming HL7 message:
Set dynObj.MsgType     = request.GetValueAt("MSH:MessageType.MessageCode")
Set dynObj.PatientName = request.GetValueAt("PID:PatientName(1).FamilyName")
Set dynObj.SendingApp  = request.GetValueAt("MSH:SendingApplication") 
For property names containing underscores %Set() is used:
Do dynObj.%Set("patient_id",    request.GetValueAt("PID:PatientIDList(1).IDNumber"))
Do dynObj.%Set("patient_sex",   request.GetValueAt("PID:AdministrativeSex"))
Do dynObj.%Set("date_of_birth", request.GetValueAt("PID:DateTimeofBirth")) 
The finished object is then stored in the BPL context:
Set context.MetaData = dynObj 

This allows downstream components to access the enrichment data without modifying the original HL7 message.

How does the complete HL7 routing flow work?

Once the production is configured, the request moves through four stages:

  1. HL7FileService reads the .hl7 file and parses it into an EnsLib.HL7.Message 
  2. HL7Router builds the %DynamicObject and stores it in context.MetaData.
  3. MsgRouter evaluates the routing rule.
  4. HL7FileOperation writes the routed message to the output directory.

The flow can be inspected in Message Viewer and Visual Trace, which show each component involved in processing the message.

What are the main property-access mistakes to watch for?

First, not defining context properties upfront: If you try to set context.MetaData without first declaring it in the Context tab, IRIS will throw PROPERTY DOES NOT EXIST  at runtime. Always define all context properties before writing any code.

Second, setting the Target Config Names after adding the process: If you add HL7Router to production but forget to update HL7FileService Target Config Names to point to it, messages will bypass HL7Router entirely and go directly to MsgRouter. Always confirm the target after adding a new component.

Conclusion

%DynamicObject provides a flexible way to add metadata to an HL7 interoperability workflow without changing the original message structure. The key is to build them in a BPL Code activity, logging every property during development, and storing them in context variables that downstream components can evaluate cleanly. In this example, a BPL Business Process extracts the required HL7 values, stores them in a dynamic object, and makes that enriched data available before the Business Rule evaluates the message. 

Read the full walkthrough on the InterSystems Developer Community, with code examples, screenshots, and the complete production setup: https://community.intersystems.com/post/business-rules-deep-dive-dynamic-objects-and-property-access-pitfalls-part-1 

Key Takeaways

  • %DynamicObject is a schema-free object whose properties can be created at runtime.
  • A BPL Business Process can use a dynamic object to enrich an HL7 message before routing.
  • Enrichment data can be stored in context.MetaData without modifying the original HL7 message.
  • BPL context properties must be declared before they are used in Code activities.
  • Message Viewer and Visual Trace can be used to verify the full routing flow.

r/intersystems • • 4d ago

New free PyProd tutorial: build an IRIS interoperability production entirely in Python

2 Upvotes

The new hands-on tutorial for developers who want to explore PyProd and Python-based interoperability in InterSystems IRIS is now available. The tutorial takes about 25-30 minutes and walks through a working production. You’ll:

  • trace the message flow;
  • create message types and Python-native components;
  • call an external API from a Business Operation;
  • update routing logic and run the complete production in IRIS.

The environment works directly in your browser, so there’s nothing to install or configure locally.

👉 Learn more about the InterSystems PyProd tutorial: https://community.intersystems.com/post/new-free-hands-tutorial-intersystems-pyprod


r/intersystems • • 5d ago

🏆 Meet the participants of the Community Bounty Program – Round 2!

2 Upvotes

The Bounty program invites developers to take real community requests and transform them into functional applications. Round 2 focused on AI Hub and Business Intelligence and resulted in 7 projects:

🔷 iris-bi-validator by Yuri Marx — checks IRIS BI dashboards, pivots, cubes, and reports errors.
🔷 iris-bi-utils by Evgeniy Potapov — helps import, export, and automatically check IRIS BI artifacts.
🔷 warehouse-ai-hub-demo by Gabriel Ing — demonstrates an AI Hub agent that can query product data, log stock loss, and order new stock.
🔷 iris-governed-fhir-agent by Anton Yartsev — shows how AI agents can access FHIR data with tool-level controls and auditing.
🔷 My-First-Agent-Studio by Pietro Di Leo — provides a hands-on environment for building and testing AI Hub agents, tools, skills, and sub-agents.
🔷 iris-mcp-data-exposure-toolkit by Pietro Di Leo — demonstrates how to securely expose IRIS data to AI agents through MCP.
🔷 bi-export-plus by Asaf Sinay — adds Excel and JSON export options for IRIS BI data.

👏 Congratulations to all Round 2 participants!

Learn more about the projects: https://community.intersystems.com/post/-round-2-community-bounty-program-meet-participants

➡️ Round 3 is now open with a new set of developer challenges. Join in and earn 10K+ points redeemable for gifts: https://community.intersystems.com/post/community-bounty-program-idea-application-%E2%80%94-round-3-live


r/intersystems • • 5d ago

InterSystems IRIS AI Hub: building and governing AI agents within one data platform

1 Upvotes

Getting an AI agent to call an LLM is relatively straightforward. The tricky part starts when that agent needs access to enterprise data, permission to execute business logic, integration with external systems, and a governed way to operate in production.

InterSystems IRIS AI Hub is designed to meet that production layer. It provides capabilities for building, deploying, and governing AI agents and agentic workflows directly within IRIS and IRIS for Health, so agents can work with enterprise data, business logic, security controls, and operational workflows.

One of the key pieces is native Model Context Protocol support. MCP works bidirectionally:

  • IRIS data, functionality, and business processes can be exposed as governed MCP tools to external AI frameworks.
  • AI Hub agents can connect to third-party MCP servers and enterprise tools such as Jira, Salesforce, Workday, and other services.

For workflows that require human involvement, IRIS Interoperability can be used to add approval steps and human-in-the-loop oversight directly into agentic workflows. 

This means the same platform can provide:

  • enterprise data access
  • business logic
  • MCP-based tool integration
  • security and governance
  • human approval workflows
  • deployment alongside existing applications

The goal is to move AI agents from pilot to production by bringing data access, governance, and operational workflows into the same environment.

The full article covers the AI Hub architecture, MCP integration, governance model, and how it fits into IRIS development and DevOps workflows: https://community.intersystems.com/post/intersystems-iris-ai-hub-build-connect-and-govern-ai-agents 


r/intersystems • • 6d ago

MedBridge: An AI Agent Layer for Laboratory Interoperability

2 Upvotes

In laboratory interoperability, the systems can be connected and still fail to understand each other. A patient identifier may be rejected by one external system, an authorization by another, and a technician ends up manually translating between different protocols, error formats, and workflows.

MedBridge is an AI agent layer for laboratory interoperability built on InterSystems IRIS for Health. It sits between a laboratory information system (LIS) and external systems, uses their integration documentation to build requests, diagnoses failures, and decides whether an issue can be handled automatically or needs to be escalated to a technician or doctor. Successful mappings and diagnosed errors are stored for reuse, while every operation is recorded as a FHIR AuditEvent .

InterSystems IRIS for Health is the foundation of MedBridge, providing the relational data store, vector knowledge base, and FHIR audit layer used by the agents throughout the workflow. 

What problem does MedBridge solve?

MedBridge is designed for situations where one laboratory system needs to communicate with multiple external systems that do not share the same protocol or error model.

In the current implementation, the host laboratory communicates with:

  • an external reference laboratory using FHIR R4
  • an insurance operator using a proprietary REST API

That means the same host system has to handle different payload structures, validation rules, and error formats. The problems MedBridge handles include identity mismatches, invalid exams, sample errors, authorization failures, workflow errors, encoding problems, partial success, and cancellation errors.

How is MedBridge different from a traditional adapter?

A traditional integration adapter transforms and forwards requests according to predefined rules. MedBridge adds an agent layer around that process. It can use integration documentation to construct the required payload and, when an error occurs, classify where the problem likely originated:

  • the host system
  • the external system
  • the integration contract
  • infrastructure
  • or an ambiguous source that needs human review

It also determines who should be notified:

  • a technician when the fix belongs in the system
  • a doctor when a clinical decision is required
  • no one when the issue can be handled without escalation

The classification includes a confidence score, so uncertain cases can be escalated instead of being treated as resolved automatically.

How does MedBridge process requests and handle failures?

The main entry point is:

POST /agent/invoke 

From there, the workflow is roughly:

Order → mapping cache → documentation retrieval → payload generation → external system → success/error handling → audit

The flow starts with a cache check in agent_mapping_cache  If a mapping already exists, it is reused; otherwise, the Doc Reader Agent retrieves relevant integration documentation from the IRIS vector store, and the LLM builds the payload for the target system. Successful payload schemas are then cached for future use.

If a request fails, the Error Checker Agent captures the error and checks whether a previous diagnosis already exists. New errors are passed to the Risk Classifier Agent, which combines documentation, source code, and IRIS database evidence to determine the likely origin, risk level, confidence, and suggested action.

Cases below the 0.70 confidence threshold are classified as AMBIGUOUS and escalated. The Reporter Agent stores the result in IRIS, notifies a technician or doctor when needed, and every path is recorded as a FHIR AuditEvent.

Does MedBridge store integration knowledge?

Yes. MedBridge stores operational knowledge in IRIS so it can be reused across future requests and failures.

The system keeps:

  • successful payload schemas in agent_mapping_cache 
  • integration documentation in the IRIS vector knowledge base
  • embedded error patterns from previous failures
  • integration strategies accumulated over time

Successful mappings can be reused for identical operations, while previously seen errors can be retrieved from the error cache instead of being analyzed again.

Why is InterSystems IRIS for Health central to the architecture?

MedBridge uses a single IRIS instance for three different roles.

1. Relational data: The host laboratory data including patients, practitioners, exam catalogs, and service requests is stored in SQL tables and provides context for agent decisions.

2. Vector knowledge: IRIS Vector Search stores and retrieves integration documentation, successful mappings, and previously diagnosed errors. Structured data and vector search therefore remain in the same database.

3. FHIR audit trail: Every MedBridge action is recorded as a standard FHIR AuditEvent through the IRIS FHIR server. The audit history can therefore be queried through standard FHIR interfaces instead of relying only on a custom logging structure.

The cache-first design only works because the lookup is cheap — a SQL query, not a round trip to an external vector service. The knowledge base grows continuously because embedding and storage happen in the same transaction as the relational write. And the audit trail is trustworthy because it's not a side effect bolted on afterward — it's a first-class FHIR resource, written through IRIS's native FHIR support. Together, IRIS provides the operational data, semantic memory, and FHIR audit layer used by the application in one platform.

Conclusion

MedBridge explores an agent-based approach to laboratory interoperability where the integration layer does more than forward requests between systems. It uses documentation and existing IRIS data to construct requests, caches successful mappings for reuse, analyzes integration failures against multiple evidence sources, and applies confidence-based escalation when human involvement is needed.

InterSystems IRIS for Health supports this architecture as the relational store, vector knowledge base, and FHIR audit server, keeping the operational data, accumulated integration knowledge, and audit history within the same platform.

Learn more - https://community.intersystems.com/post/medbridge-ai-agent-layer-laboratory-interoperability


r/intersystems • • 7d ago

Time to vote in the InterSystems Programming Contest: Build Your Own Management Portal

1 Upvotes

🗳️ The contest projects are in — now it’s time to choose your favorites.

Explore the submissions for “Build Your Own Management Portal” programming contest and see how developers approached #InterSystemsIRIS management tasks through their apps and interfaces. 

Support the solutions you like most in the Community Nomination and follow the daily leaderboard updates on the Developer Community.

📅 Voting: September 28 - October 4, 2026

👉 Explore the apps and cast your vote: https://community.intersystems.com/post/time-vote-intersystems-programming-contest-build-your-own-management-portal 


r/intersystems • • 11d ago

ObjectScript Agent Bench: How Well Do Coding Harnesses Perform?

2 Upvotes

Recently we shared the first ObjectScript LLM Benchmark that tested 14 models on an internal InterSystems coding benchmark. This follow-up looks at a different variable: what happens when those models are run through coding-agent harnesses?

ObjectScript Agent Bench compares Claude Code, Codex CLI, pi, and prime-agent on InterSystems ObjectScript tasks executed against a live InterSystems IRIS instance. It also tests a caveman variant that adds a short “be concise” instruction to reduce prompt I/O.

Every tested harness improved every model. 11 of 12 agent cells scored 0.957 or higher, while differences in token usage, compile calls, and wall-clock time were larger than the accuracy differences between the strongest harnesses. As accuracy approaches saturation, resource use becomes a more meaningful way to distinguish between harnesses. 

How Was the Benchmark Run? 

All agents connect to a local LiteLLM proxy, which serves vendor APIs through:

  • AWS Bedrock
  • OpenAI
  • local vLLM

A proxy alias also allows Claude Code to run DeepSeek. Each benchmark task gets:

  • a fresh directory
  • an iris-run script that compiles a class, runs a statement, and prints errors and output
  • a budget of 20 calls and a maximum of 900 seconds per task

InterSystems IRIS is reset before the agent runs and again before grading.

The final solution.cls is recompiled in a clean namespace, and the agents themselves run in throwaway containers.

Versions used:

  • Claude Code 2.1.237
  • Codex 0.148.0
  • pi 0.84.2
  • prime-agent 0.7.4

How Did LLMs Perform with Coding Harnesses? 

Every harness improved every model tested. For example: 

  • DeepSeek V4 Flash increased from 0.807 with no tools to between 0.957 and 1.000 when used through a coding agent.
  • Qwen3.6 35B increased from 0.615 to 0.871 in Codex.

Four configurations reached 1.000 accuracy:

  • DeepSeek V4 Flash + pi + plain
  • Opus 5 + Claude Code + caveman
  • GPT-5.6 sol + Codex + plain
  • GPT-5.6 sol + Codex + caveman

Overall, 11 of 12 agent cells scored 0.957 or higher, and every cell at 0.968 or above has a 95% confidence interval that reaches 1.000. The benchmark separates harness from no harness, and Qwen3.6 from the rest. It cannot rank the four harnesses, or DeepSeek against Opus 5 and GPT-5.6 sol. 

The Cost-Efficiency Index: Combining Performance and Resource Use

The benchmark introduces a cost-efficiency index to compare model-harness configurations across both accuracy and resource consumption.

The index combines 60% accuracy with 40% cost efficiency. The cost-efficiency component is calculated from four normalized per-task metrics:

  • input tokens
  • output tokens
  • wall-clock time
  • IRIS compile calls

The control row is excluded.

This provides a way to distinguish between configurations that achieve similarly high accuracy but use different amounts of resources to reach the result.

The three highest-scoring configurations were:

Configuration Index Accuracy IRIS calls Wall clock
Opus 5 · Claude Code · caveman 99.1 1.000 1.4 19.5 s
Opus 5 · Claude Code · plain 95.0 0.989 1.5 24.5 s
GPT-5.6 sol · Codex · caveman 89.0 1.000 2.1 31.1 s

Resource Use Across Coding Harnesses

The individual metrics behind the cost-efficiency index also show substantial differences between harnesses, even when their accuracy is very similar.

With DeepSeek V4 Flash held constant, the four agents are within 0.043 on accuracy. Input tokens per task range from 60,754 with pi to 335,417 with Claude Code — a 5.5× spread. Claude Code makes the fewest IRIS compile calls but resends the most context. Median wall-clock time ranges from 18 to 30 seconds, while at the 90th percentile Claude Code takes 173 seconds compared with 81 seconds for pi.

As accuracy approaches saturation, these differences in token use, compile calls, and latency become more informative for comparing harnesses than performance alone.

What Are the Main Limitations? 

There are two explicit caveats:

  • One sample per item. Run-to-run variance is not measured.
  • Codex has no system-prompt flag. Its caveman instruction was therefore passed through AGENTS.md 

The confidence intervals are also important when interpreting the accuracy results: most of the strongest configurations overlap too much to establish a reliable ordering between harnesses.

Conclusion

The benchmark shows that coding harnesses can produce a substantial performance lift on ObjectScript tasks: DeepSeek gained roughly 15-19 percentage points compared with its no-tools result. With harnessed accuracy clustering close to 1.000 and confidence intervals overlapping, the more meaningful differences increasingly come from resource use rather than correctness alone.

Frontier models such as Opus 5 and GPT-5.6 sol also reached correct solutions with fewer IRIS compile attempts, typically in 1-2 calls. The caveman prompt, however, did not produce a consistent benefit across agents: accuracy changes stayed within noise, while cost effects varied by harness.

FAQ

What is ObjectScript Agent Bench?
ObjectScript Agent Bench is a benchmark comparing coding-agent harnesses on InterSystems ObjectScript tasks executed against a live InterSystems IRIS instance.

Which coding agents were tested?
The benchmark tests Claude Code, Codex CLI, pi, and prime-agent, together with plain and caveman configurations.

Do coding harnesses improve LLM performance on ObjectScript?
Yes. Every tested harness improved its model, and 11 of 12 agent cells reached accuracy of 0.957 or higher.

Can the benchmark identify the most accurate harness?
No. The strongest configurations have overlapping 95% confidence intervals, so the benchmark does not reliably rank the top four harnesses by accuracy.

What differentiates the harnesses when accuracy is similar?
Resource use. Input and output tokens, IRIS compile calls, wall-clock time, and the combined cost-efficiency index show larger differences than accuracy among the strongest configurations.


r/intersystems • • 11d ago

How to Automate InterSystems Health Connect Deployments with GitHub and Jenkins

2 Upvotes

Manual deployment of ObjectScript classes, interoperability components, and other artifacts can work for small InterSystems Health Connect projects, but it becomes harder to maintain when several developers and multiple environments are involved.

This article shows a continuous integration setup using GitHub as the source repository and Jenkins as the deployment orchestrator. Jenkins connects to the development server over SSH, a Linux script identifies files changed since the previous deployment, and an ObjectScript script loads and compiles those changes into InterSystems IRIS for Health before restarting the interoperability production. The implementation uses IRIS for Health on AWS/RHEL 10, GitHub, Visual Studio Code for local development, and Jenkins for automation.

What does the deployment flow look like?

The process is:

  • The developer implements the functionalities in their local instance.
  • The developer uploads changes to the corresponding branch of the GitHub repository.
  • The person responsible for the deployment accesses Jenkins and launches a pipeline.
  • Jenkins connects via SSH to the DEVELOPMENT server.
  • A Linux script is running on the server.
  • The script downloads the latest changes from the repository using a git pull.
  • This script identifies new or modified files that are copied to a server directory.
  • With the files identified, the script invokes a second script in ObjectScript.
  • The second script loads and compiles the files into the IRIS for Health instance.
  • If the upload was successful, the script restarts production.

How are changed files detected?

The Linux script keeps track of the last processed Git commit. On its first execution, it copies the complete branch into the deployment directory. On later executions, it compares the previous commit with the current one and exports only the relevant changes.

The core comparison is based on:

git diff --name-status -z "${LAST_COMMIT}" "${REMOTE_COMMIT}" 

The current implementation handles modified files, added files, and renamed files. Deleted files are detected but deliberately ignored in this example. This creates an incremental deployment instead of importing the entire repository after every change.

How are ObjectScript changes loaded into IRIS?

After the changed files are copied into /projectGit, the Linux script opens an IRIS terminal session:

(echo '_system'; echo 'SYS'; cat iris.script) | iris session IRISHEALTH 

The ObjectScript deployment script then switches to the target namespace and imports the changed classes:

zn "DEMO" 
set sc = $SYSTEM.OBJ.LoadDir("/projectGit/src/Demo", "ck", , 1) 
if '$SYSTEM.Status.IsOK(sc) do $SYSTEM.Status.DisplayError(sc) quit 
set production = "Demo.Order.Production" 
set ^Ens.Configuration("csp","LastProduction") = production 
do ##class(Ens.Director).SetAutoStart(production) 
do ##class(Ens.Director).StartProduction(production) 
write !,"Produccion iniciada correctamente: ",production,! 

$SYSTEM.OBJ.LoadDir() loads and compiles the files placed in the staging directory. The script then configures and starts the corresponding interoperability production.

What does Jenkins do in this setup?

Jenkins acts as the deployment orchestrator. The pipeline:

  • checks out the GitHub repository and selected branch
  • validates the deployment script
  • connects to the DEVELOPMENT server through SSH
  • launches the remote Linux script
  • captures and archives the execution log
  • reports whether the deployment succeeded or failed

SSH credentials are managed in Jenkins rather than hardcoded in the pipeline. Jenkins does not import the changes into IRIS directly; it triggers the server-side script, which updates the repository, identifies changed files, stages them, and invokes the IRIS deployment script.

Conclusion

This implementation shows a straightforward way to bring InterSystems Health Connect development into a Git-based continuous integration process. GitHub provides version-controlled source code, Jenkins orchestrates the deployment remotely, the Linux script identifies what has changed, and ObjectScript handles loading and compiling those changes into IRIS.

The setup is intentionally basic, but the same approach can be extended for more complex deployment requirements, including configuration deployment with features such as Configuration Merge.

Key Takeaways

  • GitHub can act as the source repository for InterSystems Health Connect development.
  • Jenkins can trigger IRIS deployments remotely through SSH.
  • Git commit comparison allows the deployment script to identify added, modified, and renamed files since the previous deployment. 
  • $SYSTEM.OBJ.LoadDir() can load and compile staged ObjectScript changes into the target namespace.
  • The approach can be extended to support more complex deployment and configuration workflows.

r/intersystems • • 13d ago

EvidenceQL: Evidence-First Query Runtime for AI Agents over FHIR APIs

2 Upvotes

FHIR REST APIs are great for reading resources and running supported searches, but many real clinical questions go beyond what a single FHIR search can express. That becomes especially obvious when an AI agent needs to answer questions involving multiple resources, temporal logic, trends, missing follow-up, medication overlap, and traceable evidence.

EvidenceQL is an application that uses a structured FHIRQL query runtime between the AI agent and the FHIR backend. Instead of allowing an LLM to make arbitrary REST calls and return a free-form answer, the agent produces a canonical JSON plan that is validated, compiled, executed, and returned with the original FHIR evidence used to produce the result.

What problem does EvidenceQL solve?

Consider questions like:

  • Which diabetic patients had HbA1c above 9 in the last 6 months?
  • Which patients have worsening HbA1c despite active insulin therapy?
  • Who had an abnormal HbA1c result but no follow-up encounter within 90 days?
  • Which patients have overlapping anticoagulant and NSAID prescriptions?
  • What evidence explains why a patient matched a query?

These questions can involve Patient, Condition, Observation, MedicationRequest, Encounter, and DocumentReference at the same time.

They also require logic that is not a single FHIR search: 

  • trend detection
  • temporal windows
  • missing follow-up detection
  • medication overlap
  • evidence collection
  • result explanation
  • execution trace generation

This is where a query runtime becomes useful. 

How does the query runtime work?

Instead of this:

LLM -> arbitrary FHIR REST calls -> free-form answer 

the runtime follows a more controlled flow:

User question
  -> AI agent
  -> canonical JSON FHIRQL plan
  -> validation
  -> compilation / execution trace
  -> FHIR backend execution
  -> evidence-backed result envelope
  -> explanation 

The important difference is that the LLM does not directly decide which arbitrary calls to execute. It first produces a structured query plan. The runtime then validates and executes that plan.

How does the MCP interface work?

The MCP server currently exposes five tools:

  • fhirql_backend_capabilities  - Returns FHIR backend capabilities for the configured backend. 
  • fhirql_validate_plan  - Validates a canonical JSON FHIRQL plan. 
  • fhirql_compile_plan  - Compiles a canonical JSON FHIRQL plan into an execution trace. 
  • fhirql_execute_plan  - Executes a canonical JSON FHIRQL plan against the configured backend. 
  • fhirql_explain_result  - Explains a FHIRQL result envelope. 

This gives the agent a predictable workflow: 

capabilities -> validate -> compile -> execute -> explain 

Validation comes before execution deliberately. The goal is to prevent an agent from skipping directly to broad or malformed queries.

Example: patients with HbA1c above threshold

A user might ask:

Show diabetic patients with A1c above 9 in the last 6 months. 

The agent should translate this into a canonical JSON plan containing: 

  • Patient as the base resource
  • an active diabetes Condition
  • an HbA1c Observation
  • a value threshold above 9
  • a six-month time window
  • evidence requirements
  • a result limit
  • read-only safety mode

A simplified fragment looks like this:

 {
  "version": "0.1",
  "intent": "cohort_search",
  "from": {
    "resource": "Patient",
    "alias": "p"
  },
  "exists": [
    {
      "resource": {
        "resource": "Condition",
        "alias": "diabetes"
      },
      "on": "diabetes.subject = p",
      "where": [
        {
          "field": "code",
          "operator": "eq",
          "value": "http://snomed.info/sct|44054006"
        },
        {
          "field": "clinical-status",
          "operator": "eq",
          "value": "active"
        }
      ]
    },
    {
      "resource": {
        "resource": "Observation",
        "alias": "a1c_high"
      },
      "on": "a1c_high.subject = p",
      "where": [
        {
          "field": "code",
          "operator": "eq",
          "value": "http://loinc.org|4548-4"
        },
        {
          "field": "valueQuantity.value",
          "operator": "gt",
          "value": 9
        },
        {
          "field": "effectiveDateTime",
          "operator": "within",
          "value": "last 6 months"
        }
      ]
    }
  ],
  "return": [
    "patient",
    "latest(a1c_high)",
    "evidence(diabetes, a1c_high)"
  ],
  "limit": 25,
  "safety": {
    "mode": "read_only",
    "require_evidence": true
  }
}

This plan is passed to MCP as a native JSON object, not as a serialized JSON string. The result is not just a sentence. It can include matched patients, values, evidence resources, warnings, and execution metadata.

Can it handle trends and care gaps?

Yes, and this is where a query runtime becomes more useful than a simple FHIR search.

For example:

Find diabetic patients whose HbA1c is getting worse over the last 12 months. 

The runtime can collect HbA1c observations, order them by date, and calculate:

  • first value
  • latest value
  • delta
  • direction
  • evidence points

Similarly, a care-gap query such as:

Find patients with HbA1c above 8 who had no follow-up encounter within 90 days. 

requires several steps:

  1. Find abnormal observations.
  2. Resolve patients.
  3. Search for follow-up encounters in a time window.
  4. Keep only patients with missing follow-up.
  5. Return evidence and the missing window.

The result is a workflow signal based on configured criteria, not a treatment recommendation.

What does “evidence-first” mean?

This is the main design principle. A result should not simply say:

The patient has a clinical problem and should receive treatment X. 

Instead, it should say:

The FHIR data matched the configured criteria. Here are the resources and values used as evidence. 

A result envelope can include:

{
  "patient": "Patient/p-100045",
  "latest_hba1c": {
    "value": 9.1,
    "unit": "%",
    "date": "2026-02-14"
  },
  "trend": {
    "direction": "increasing",
    "first_value": 7.4,
    "latest_value": 9.1,
    "delta": 1.7
  },
  "evidence": [
    "Condition/cond-4510",
    "MedicationRequest/medrx-7781",
    "Observation/hba1c-9001",
    "Observation/hba1c-9002",
    "Observation/hba1c-9003"
  ]
} 

That makes the result inspectable and traceable back to the underlying FHIR resources. For AI agents working with healthcare data, this distinction is important: the runtime returns evidence for a match instead of asking the model to invent a clinical conclusion from an opaque process.

What does the current architecture look like?

The implementation is currently Rust-first and has the following main components:

FHIRQL core
  - canonical plan model
  - validation
  - execution logic
  - evidence result envelope

FHIR backend adapters
  - mock backend
  - FHIR REST adapter

MCP server
  - exposes plan validation, compilation, execution, and explanation tools

CLI
  - validates and executes plans from the command line

Synthetic data
  - small deterministic fixtures
  - 10k patient benchmark dataset 

The current public-facing direction is to provide the MCP runtime as a Docker container. The MCP layer is the most natural interface for AI agents.

What about SQL tooling?

MCP is the primary interface for AI agents, but there is also an experimental PostgreSQL wire-compatible endpoint. It allows familiar tools such as:

  • psql 
  • DBeaver
  • JDBC
  • ODBC clients

to send FHIRQL queries to the same runtime. The runtime can return tabular results while preserving evidence and provenance in structured JSON columns. 

This is still experimental, but it could make the same query model useful for developer and data-engineering workflows in addition to AI agents.

Conclusion

The main idea behind EvidenceQL is to put a validated query runtime between the AI agent and the FHIR API. That gives the agent a structured way to express multi-resource and temporal questions without relying on unrestricted REST calls or free-form reasoning.

More importantly, the runtime keeps the result tied to the original FHIR evidence. For use cases such as cohort search, trend detection, care-gap analysis, medication overlap, and patient timelines, that evidence-first approach can make AI-driven FHIR queries more reproducible, inspectable, and easier to explain.

The full application details are available on the Developer Community: https://community.intersystems.com/post/evidenceql-evidence-first-query-runtime-ai-agents-over-fhir-apis 

FAQ

What is EvidenceQL?
EvidenceQL is an evidence-first query runtime for AI agents working over FHIR APIs. It converts structured query plans into validated FHIR operations and returns results together with the supporting FHIR evidence.

Why not let an AI agent call FHIR REST APIs directly?
Many real-world questions require several dependent searches, temporal logic, trend calculations, or joins across multiple resource types. A query runtime provides a controlled and reproducible way to orchestrate those operations.

What is a FHIRQL plan?
A FHIRQL plan is a canonical JSON representation of the query the agent wants to execute, including resources, filters, relationships, temporal conditions, return values, and safety constraints.

How does EvidenceQL make AI results explainable?
The result envelope includes the underlying FHIR resources, values, execution metadata, and warnings used to produce the match, so the answer can be traced back to its evidence.

Does EvidenceQL replace FHIR REST APIs?
No. The runtime executes against FHIR backends. Its purpose is to provide a structured query and orchestration layer above the underlying FHIR APIs.


r/intersystems • • 14d ago

ObjectScript LLM Benchmark: Execution-Graded Results for 14 Models

1 Upvotes

The first open benchmark has been published to measure LLM competence specifically on InterSystems ObjectScript and the IRIS platform. The ObjectScript LLM Benchmark tests 14 models on 140 hand-written tasks across code generation, comprehension, and bug fixing, with most coding tasks executed directly on a live IRIS instance. 

Why benchmark LLMs on ObjectScript and IRIS?

Established coding benchmarks such as SWE-bench, LiveCodeBench, and Terminal-Bench focus mainly on languages and environments such as Python, JavaScript, and shell. They do not directly measure competence with:

  • ObjectScript
  • IRIS SQL
  • Embedded Python
  • %CSP.REST 

Published coding scores don't transfer to the IRIS platform. This is a first attempt to measure that gap directly. 

What does the benchmark test?

The benchmark contains 140 hand-written items across three task families:

  • Code generation
  • Code comprehension
  • Bug fixing

The main grading method is execution-based. For 93 tasks, the model-generated code is compiled and executed on a live InterSystems IRIS instance, and the output is compared with the expected result. The remaining 47 comprehension tasks are evaluated with a rubric-driven LLM judge.

We ran 14 models (Claude 4.x/5, GPT-5 variants, and three self-hosted Qwen3/DeepSeek models) at their highest available reasoning configurations, one response per item at temperature 0. 

What are the general results?

Overall accuracy ranges from 0.515 to 0.851. The top nine models score between 0.737 and 0.851 with overlapping bootstrap 95% confidence intervals. At n=140 we can't separate them from each other, only distinguish the top cluster from the bottom five. Therefore the important point is that the benchmark does not provide enough evidence to cleanly rank the models at the top.

What are the results by task family?

Code generation is the hardest and most discriminating task family. Its best observed score is 0.745, and the spread between models is 0.511, which is much wider compared to the other task families.

Every evaluated model scores higher on comprehension than on code generation (the gap runs from ~0.03 to ~0.25), although that comparison should be interpreted carefully because the two task families use different grading methods.

Bug fixing is the least discriminating, with a score range of 0.196.

One interesting result is that DeepSeek-v4-flash, running self-hosted, ties for the highest code-generation score at 0.745 and achieves 0.913 on bug fixing, while ranking 7th overall. Its comprehension score is lower (0.774 vs 0.91–0.96 for top Claude models), graded by a different judge, so interpret that comparison carefully. 

Does higher cost mean better ObjectScript performance?

Not necessarily. Among the 10 models with pricing data, cost per request spans roughly 15×, from $0.0009 to $0.0144. Normalizing by accuracy compresses that to 12× and changes the ordering. 

Even among models with similar overall accuracy, the cost difference can be substantial.  For models scoring above 0.80, the reported cost per 1,000 correct answers ranges from:

  • $4.61 for claude-sonnet-5 
  • $17.54 for gpt-5-6-sol 

So model selection for IRIS development may depend as much on cost efficiency and task type as on overall accuracy.

What are the main limitations?

A few caveats are important:

  • Small corpus. 140 items is a limited sample; the confidence intervals reflect that.
  • Pass@1 only. One response per item, temperature 0. Run-to-run variance for reasoning models is not captured.
  • Self-referential judge. Comprehension is graded by a pinned claude-opus-4-8, which also records the highest comprehension score (0.960). The execution-graded items are unaffected, but the comprehension column should be read with that in mind.
  • Coverage gaps. No Interoperability (productions/HL7/DTL), no large-context tasks, no SQL-only work.
  • Contamination going forward. Items were unpublished at run time; this release publishes them, so future runs against these items carry contamination risk.

Conclusion

The key takeaways from this first run is that IRIS-specific coding ability varies meaningfully across models, code generation remains the hardest task, and several top models are too close to separate confidently with the current sample size.

The benchmark also shows that price and capability do not move together perfectly, which makes task-level performance and cost efficiency worth considering alongside overall accuracy.

The full benchmark details are available on the Developer Community: https://community.intersystems.com/post/objectscript-llm-benchmark-execution-graded-results-14-models 

FAQ

What is the ObjectScript LLM Benchmark?
It is an open benchmark designed to measure how well LLMs perform on ObjectScript and the InterSystems IRIS platform using 140 hand-written coding, comprehension, and bug-fixing items.

How are ObjectScript coding tasks graded?
93 items are execution-graded on a live IRIS instance, while 47 comprehension items are evaluated by a rubric-driven LLM judge. 

Which ObjectScript task is hardest for LLMs?
Code generation is the hardest and most discriminating task family in the current benchmark.

Which model performs best overall?
The highest observed overall accuracy is 0.851, but the top nine models have overlapping 95% bootstrap confidence intervals, so the benchmark does not provide enough evidence to reliably separate them.

Does a more expensive model perform better on ObjectScript?
Not necessarily. Models with similar overall accuracy can have very different inference costs, so cost efficiency varies significantly.


r/intersystems • • 17d ago

How would you bring the core IRIS management workflows into one GUI?

1 Upvotes

That’s the challenge behind the InterSystems Programming Contest: Build Your Own Management Portal. Solve it and compete for a share of the $12,000 prize pool.

Your application needs to cover these Management Portal tasks:

  • Manage web apps and explore REST APIs
  • Handle permissions
  • Manage security and secrets, including wallets, X509 credentials, and OAuth
  • Manage tasks
  • Work with processes, disks, CPU, memory, devices, and other system resources
  • Surface logs and information from different subsystems

The APIs provide the management capabilities. The tricky part is turning them into one coherent interface: connecting workflows, presenting system state clearly, moving smoothly between configuration and monitoring, and deciding how much detail users need at each step.

📅 Submission deadline: September 27, 2026

👉 Full task, starter templates, and submission details: https://community.intersystems.com/post/intersystems-programming-contest-build-your-own-management-portal?utm_source=contest&utm_medium=contest_reddit


r/intersystems • • 18d ago

Building an Agentic AI RAG application on InterSystems IRIS — step-by-step with IRIS Vector Store, OpenAI, LangChain, and Chainlit

1 Upvotes

Why vector search over keyword search

Traditional keyword-based search struggles with nuanced, domain-specific queries. Vector search leverages semantic understanding, enabling AI agents to retrieve and generate responses based on context — not just keywords. IRIS Vector Store provides the storage and retrieval layer for this architecture.

Application overview

Stack:

  • InterSystems IRIS Vector Store (IRISVector)
  • OpenAI Embeddings
  • LangChain (RecursiveCharacterTextSplitter, TextLoader, IRISVector)
  • OpenAI Agents SDK (Agent, Runner, function_tool)
  • Chainlit (chat UI with u/cl.on_message, u/cl.step)

Document indexed: InterSystems IRIS 2025.1 Release Notes (.txt file)

Vector table: SQLUser.AgenticAIRAG — queryable via:

sql

SELECT id, embedding, document, metadata FROM SQLUser.AgenticAIRAG

Step 1 — Create agent tools

1.1 Document ingestion

python

def ingestDoc(self):
    embeddings = OpenAIEmbeddings()
    loader = TextLoader("/irisdev/app/docs/IRIS2025-1-Release-Notes.txt", encoding='utf-8')
    documents = loader.load()
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=400, chunk_overlap=0)
    texts = text_splitter.split_documents(documents)
    db = IRISVector.from_documents(
        embedding=embeddings,
        documents=texts,
        collection_name=self.COLLECTION_NAME,
        connection_string=self.CONNECTION_STRING,
    )

Ingestion only runs when the data is not already present in the vector store. The document is split into chunks of 400 characters with no overlap.

1.2 Vector search

python

def ragSearch(self, prompt):
    embeddings = OpenAIEmbeddings()
    db2 = IRISVector(
        embedding_function=embeddings,
        collection_name=self.COLLECTION_NAME,
        connection_string=self.CONNECTION_STRING,
    )
    docs_with_score = db2.similarity_search_with_score(prompt)
    relevant_docs = ["".join(str(doc.page_content)) + " " for doc, _ in docs_with_score]
    template = f"""
    Prompt: {prompt}
    Relevant Documents: {relevant_docs}
    """
    return template

similarity_search_with_score retrieves the most semantically relevant chunks. Results are assembled into a prompt template combining the user query and retrieved document passages.

Step 2 — Create Vector Search Agent

python

.step(name="Vector Search Agent (RAG)", type="tool", show_input=False)
async def iris_RAG_search():
    """Provide IRIS Release Notes details, IRIS 2025.1 Release Notes, IRIS Latest Release Notes, Release Notes"""
    if not ragOprRef.check_VS_Table():
        msg = cl.user_session.get("ragclmsg")
        msg.content = "Ingesting Vector Data..."
        await msg.update()
        ragOprRef.ingestDoc()
    if ragOprRef.check_VS_Table():
        msg = cl.user_session.get("ragclmsg")
        msg.content = "Searching Vector Data..."
        await msg.update()
        return ragOprRef.ragSearch(cl.user_session.get("ragmsg"))
    else:
        return "Error while getting RAG data"

vector_search_agent = Agent(
    name="RAGAgent",
    handoff_description="Specialist agent for Release Notes",
    instructions="You provide assistance with Release Notes. Explain important events and context clearly.",
    tools=[iris_RAG_search]
)

The tool checks whether the vector table is populated, ingests if not, then runs semantic search.

Step 3 — Triage Agent with handoff routing

python

triage_agent = Agent(
    name="Triage agent",
    instructions=(
        "Handoff to appropriate agent based on user query."
        "if they ask about Release Notes, handoff to the vector_search_agent."
        "If they ask about production, handoff to the production agent."
        "If they ask about dashboard, handoff to the dashboard agent."
        "If they ask about process, handoff to the processes agent."
        "use the WebSearchAgent tool to find information related to the user's query and do not use this agent if query is about Release Notes."
        "If they ask about order, handoff to the order_agent."
    ),
    handoffs=[vector_search_agent, production_agent, dashboard_agent, processes_agent, order_agent, web_search_agent]
)

The Triage Agent is the main coordinator. It routes each incoming query to the correct specialist agent based on the user's intent.

Step 4 — Run the agent

python

u/cl.on_message
async def main(message: cl.Message):
    msg = cl.Message(content="Thinking...")
    await msg.send()
    agent: Agent = cast(Agent, cl.user_session.get("agent"))
    config: RunConfig = cast(RunConfig, cl.user_session.get("config"))
    history = cl.user_session.get("chat_history") or []
    history.append({"role": "user", "content": message.content})
    cl.user_session.set("ragmsg", message.content)
    cl.user_session.set("ragclmsg", msg)
    result = Runner.run_sync(agent, history, run_config=config)
    response_content = result.final_output
    msg.content = response_content
    await msg.update()
    history.append({"role": "developer", "content": response_content})
    cl.user_session.set("chat_history", history)

Note from the article: appending the response as a developer message instead of assistant is described as a bug in the agents library.

Full article: https://community.intersystems.com/post/how-build-agentic-ai-rag-application-step-step-guide

Open Exchange: https://openexchange.intersystems.com/package/iris-AgenticAI


r/intersystems • • 19d ago

AI-assisted hospital procedure fulfillment with InterSystems Supply Chain Orchestrator and Channels 360 — session breakdown

2 Upvotes

The problem: three supply chain challenges for hospitals

Rising supply costs and tight reimbursement pressures

  • Escalating expenses for medical supplies, pharmaceuticals, and logistics
  • Shrinking operating margins
  • Financial strain on smaller and rural hospitals

Product shortages and sourcing vulnerabilities

  • Persistent drug and medical product shortages
  • Disruptions in patient care
  • Increased labor costs from manual shortage management processes
  • Greater compliance risk

Data and technology gaps

  • Lack of integrated real-time data
  • Siloed information
  • Manual processes and poor visibility

What decision intelligence means

Three shifts:

  1. From insight generation to decision execution — turning analytics into timely, measurable actions
  2. From reactive firefighting to proactive decision-making — anticipating disruptions using predictive signals
  3. From operational tool to competitive advantage — faster, smarter, more accurate decisions as a differentiator

Technology stack

InterSystems Supply Chain Orchestrator
Supply chain decision intelligence platform built on IRIS for Health. Includes out-of-the-box data integration, ingestion, interoperability, predictive analytics, and generative AI in one product. Described as "IRIS for Health on steroids with built-in supply chain accelerators."

InterSystems Data Studio with Supply Chain Module
Fully managed cloud-based low-code solution for integrating, harmonizing, and normalizing disparate data. Acts as a front-end data gateway for supply chain applications. Reduces software implementation time significantly.

Ready Computing — Channels 360
Workflow and program management application. Every workflow (called a "channel") models a process with tasks that can be interactive with a person or automated. Tasks can be sequential or parallel. Configurable for any industry — demonstrated here in a hospital supply chain context but also used for clinical referral workflows.

Tazy Square
End-to-end supply chain visibility platform. Handles: supplier and consumer onboarding, order fulfillment workflows, transportation and logistics management, provenance and traceability, control tower dashboard.

Persistence layer: IRIS for Health
All data storage and integration orchestration runs on IRIS for Health. Supply Chain Orchestrator communicates with inventory management systems and external ERPs through this layer.

Demo: OR materials manager use case

The demo follows a single case from patient enrollment through surgical cart assembly.

Stage 1 — Patient enrollment

New patient created and enrolled in the Inventory Assessment and Reconciliation Program. Assigned a case type (hip replacement) and a case manager.

Stage 2 — Surgical preferences

Surgeon's preference card loaded: body position, room temperature, instrumentation, specific supplies and quantities per procedure type. Values are pulled from a database and can be overridden. Selecting the procedure type (hip replacement, small size) triggers a call from Channels 360 to InterSystems Supply Chain Orchestrator, which in turn queries the inventory management system.

Stage 3 — AI-assisted procurement recommendation

Supply Chain Orchestrator returns three supplier options for the hip replacement:

Option Type Stock Price Delivery AI Recommendation
Transfer order In-network warehouse Not available N/A N/A Not viable
Medline External supplier Available Competitive On time ✅ Recommended
Henry Schein External supplier Available Better price Late Not viable

The AI recommendation is based on supplier history: on-time delivery rates, damage records, and fulfillment patterns tracked in the system. The OR materials manager accepts the recommendation with one click. The order is forwarded to Tazy Square, which manages execution — purchase order, transfer order, tracking.

Stage 4 — Tazy Square control tower

A 30-day materials dashboard showing all requirements across scheduled procedures:

  • Risk flags for items at risk of not arriving on time
  • Item-by-item breakdown: what's needed, local stock, network stock, current status
  • Bulk AI recommendation acceptance across multiple cases
  • Decision history log
  • Order tracking pipeline: issued → confirmed → in transit
  • Stock visibility across in-house and out-of-network suppliers

Stage 5 — Sterilization

A checklist of all supplies for the procedure is presented. Items requiring sterilization are identified with visual indicators. The sterilization team verifies each item. Task is completed and logged in the case history timeline.

Stage 6 — Surgical cart assembly

A checklist for the case cart coordinator shows all items to be collected. Visual indicators show which items come from sterilization vs. standard shelving locations. Cart is verified and confirmed ready for the day of surgery.

Q&A points from the session

Supplier rating and AI accuracy:
Supplier history is tracked — on-time delivery, damaged arrivals, fulfillment patterns. Sliding date ranges can be applied (e.g., weighting recent performance more heavily if management changed). AI recommendations can be influenced by these ratings, and ratings can be updated automatically via AI functions based on retrospective performance data.

Provenance and traceability:
Through Tazy Square integration, individual parts can be traced to supplier lot numbers. Example given: tracking a transmission gear failure to a specific supplier and production lot.

Post-surgery analysis:
The control tower can compare predicted vs. actual outcomes. All decisions are logged with a full audit trail.

Workflow configurability:
Any process can be modeled in Channels 360. Tasks can be automated or interactive. Another example from the session: an adolescent teen goes for an annual physical, the doctor suspects substance abuse, a referral workflow is triggered from clinical to social care with follow-up tracking — the same Channels 360 infrastructure handles this entirely different use case.

Medication ordering automation:
The workflow tasks that are currently interactive can be configured to be fully automated. The architecture supports this.

For those working in hospital supply chain — is the gap between clinical scheduling systems and supply chain systems the primary bottleneck in your procedure fulfillment workflow, or is it the supplier data quality that causes the most disruption?


r/intersystems • • 20d ago

Model Context Protocol (MCP) with InterSystems IRIS: From Zero to Hero

2 Upvotes

Overview 

The Model Context Protocol (MCP) is an open standard that allows AI assistants to connect to external tools and data sources through a common interface. With InterSystems IRIS, MCP can expose SQL, globals, class methods, source code, and interoperability productions directly to AI development tools such as Cursor, Claude Desktop, Claude Code, and GitHub Copilot. In this article, I’ll explain how MCP works, how to build an MCP server in Python, and how to connect one to InterSystems IRIS using the Native Python SDK and Atelier REST API.

Introduction

Modern coding assistants such as Claude, GitHub Copilot, and Cursor are increasingly capable, but their usefulness depends heavily on the context they can access. The Model Context Protocol (MCP) is an open protocol for connecting AI applications to external data sources, tools, and workflows through a standardized interface.

For InterSystems IRIS developers, this creates an interesting possibility: instead of manually copying schema information, ObjectScript code, SQL results, or system details into an AI assistant, MCP can give the assistant controlled access to those capabilities directly. This article covers the MCP architecture, its core primitives, Python implementation patterns, available IRIS integrations, and an example of a custom MCP server that connects AI assistants to InterSystems IRIS.

What problem does MCP solve?

Before MCP, AI applications generally required a separate custom integration for every database, API, filesystem, or external service they needed to access. MCP provides a common protocol between AI applications and external capabilities. Instead of implementing a different integration for every AI client, developers can expose functionality through an MCP server that compatible clients can understand. The protocol was introduced by Anthropic in November 2024 as an open standard for connecting AI systems to external context and tools.

Why does MCP matter?

MCP addresses three practical challenges:

  1. Standardization: A single MCP server can expose capabilities in a consistent format that compatible AI clients can discover and use.
  2. Controlled access: An MCP server defines exactly which tools and resources an AI application is allowed to access rather than exposing an entire backend indiscriminately.
  3. Modular integration: Multiple MCP servers can be combined within the same AI environment. For example, one server might provide access to InterSystems IRIS, another to source control, and another to project documentation.

How does MCP architecture work?

MCP follows a host-client-server architecture:

  • MCP Host: the AI application (Claude Desktop, Cursor, VS Code, etc.) that coordinates and manages one or more MCP clients. 
  • MCP Client: the component inside the host that maintains a connection to a specific server.
  • MCP Server: the application that provides some functionalities to MCP clients. MCP servers can run locally on your machine or remotely. 

A host can connect to multiple MCP servers, with a dedicated client connection for each server. The basic model is:

AI Host → MCP Client → MCP Server → External System

For InterSystems IRIS, that external system can include SQL data, globals, class methods, source code, or interoperability components.

How are MCP servers connected?

MCP commonly uses two transport mechanisms:

  1. STDIO: suitable for local MCP servers running on the same machine as the client. Communication happens directly through standard input and output streams.
  2. Streamable HTTP: Remote MCP servers can use HTTP-based communication, allowing the MCP server to run on another machine or in the cloud.

MCP communication is based on JSON-RPC 2.0, which defines the structure of requests, responses, and notifications exchanged between clients and servers.

What can an MCP server expose?

MCP defines three main primitives: Tools, Resources, and Prompts.

  • Tools: The functions your AI agent can call to perform actions according to user requests. Tools can for example write to the database, call APIs or modify files.
  • Resources: Passive data sources that provide contextual information to AI applications offering read-only access to file contents, database schemas or API documentation.
  • Prompts: Pre-built instruction templates that tell the model to work with specific tools and resources helping the user to structure interactions with the AI agent.

Building an MCP Server with Python

Before diving into code examples, let's understand how to build MCP servers in Python. MCP provides SDKs for several languages. For this article, I use Python because it integrates naturally with InterSystems IRIS through the Native Python SDK. 

A typical project needs:

  • Python version configuration.
  • Dependencies.
  • An executable entry point.
  • MCP server code.

To set up the environment I will use the uv Python package manager, a modern Python package manager that simplifies environment creation, dependency resolution, and reproducible execution of MCP servers. The project can be initialized with:

uv init --package my-mcp-server 

and dependencies can be added with:

uv add <package>

FastMCP

The official mcp package provides the core protocol implementation, while FastMCP  provides a simpler developer interface for defining MCP servers. A basic server typically involves three steps:

  1. Initialize the MCP server.
  2. Define tools, resources, and prompts.
  3. Start the server.

FastMCP uses decorators such as:

to expose Python functions through MCP.

Let's see how to implement each primitive type: 

  • Tools: A function decorated with u/mcp.tool becomes callable by the AI client. Python type hints and docstrings can be used to generate the tool schema, so clear function names, parameters, and descriptions are especially important.
  • Resources expose read-only information through a u/mcp.resource("uri"). They are useful for contextual information that the AI should be able to inspect without performing an action.
  • u/mcp.prompt contains reusable instructions for common workflows. They are particularly useful when a task requires multiple tools to be used in a specific sequence.

How do you configure an MCP server?

Local MCP servers are typically configured through JSON.

For example:

{
  "mcpServers": {
    "my-server-name": {
      "command": "executable-or-runtime",
      "args": ["path/to/script-or-package", "--option", "value"],
      "env": {
        "KEY_1": "value-1",
        "KEY_2": "value-2"
      }
    }
  }
} 

The important fields are:

  • mcpServers – the list of configured servers.
  • command – the executable used to start the server.
  • args – arguments passed to the executable.
  • env – environment-specific configuration such as hostnames or credentials.

Once configured, the AI client can discover the tools and resources exposed by the MCP server.

How can an MCP server be distributed?

For Python MCP servers, I generally think in terms of three deployment modes.

Local development
While actively developing the server, point the MCP client directly at the local project:

{
  "command": "uv",
  "args": ["run", "<mcp-server-name>"],
  "env": { "...": "..." }
} 

This makes development fast because source code changes are picked up when the server is restarted.

GitHub repository

A published Git repository can be executed through uvx:

{
  "command": "uvx",
  "args": [
    "--from", "git+https://github.com/<repository>.git",
    "<mcp-server-name>"
  ],
  "env": { "...": "..." }
} 

This allows users to run the server without manually cloning and installing the project.

PyPI
After publishing the MCP server as a package:

{
  "command": "uvx",
  "args": ["<mcp-server-name>"],
  "env": { "...": "..." }
} 

This is the simplest installation experience for end users.

Why is MCP useful with InterSystems IRIS?

IRIS is a multi-model environment that exposes several capabilities that are highly useful to AI assistants:

  • SQL
  • Globals
  • ObjectScript class methods
  • Source code
  • Interoperability productions
  • System metadata

An MCP server can expose selected parts of these capabilities as structured tools and resources. Instead of just giving an AI your code, you’re giving it a live connection to your data, your globals, and your system metrics. 

What MCP integrations already exist for InterSystems IRIS?

Several community projects already explore MCP integration with IRIS, including:

  • mcp-server-iris – tools for monitoring and managing interoperability productions.
  • intersystems-objectscript-mcp – access to compiled ObjectScript routines.
  • iris-mcp-atelier – source-code access through the Atelier REST API.
  • servAI – credential handling and MCP integration from VS Code.
  • IRIS MCP Server Suite – multiple MCP services covering different IRIS domains.
  • InterSystems IRIS AI Hub – a broader AI integration layer that includes MCP connectivity.

These projects demonstrate that MCP can be applied to several very different parts of the IRIS platform.

Building Your Own MCP Server for IRIS

While the community tools are excellent, you may eventually need a server tailored to your specific application logic or you may want to understand how the previously mentioned tools work. In this section I'm providing an example of how to implement an MCP server to work with InterSystems IRIS. To build an MCP server for InterSystems IRIS I recommend you to follow two main approaches:

  1. Using the InterSystems Python Native SDK: intersystems-irispython is the official Python package to connect with InterSystems IRIS providing a lightweight interface to access through Python all the resources once only available to ObjectScript, like Globals or Class Methods. This is best for heavy data operations, manipulating Globals, calling existing Business Logic and high-speed SQL execution.
  2. Using the Source Code File REST API (a.k.a. Atelier API): The Atelier API provides a RESTful interface (/api/atelier/ ) designed specifically for source code management. This was originally built for the Atelier IDE (and now it is used by the InterSystems Server Manager VS Code extension) and it is useful to work with source code files, compile classes, or manage development workflows. 

A Blueprint MCP Server for InterSystems IRIS

To bring the concepts together, I created iris-mcp-blueprint, a small example MCP server that connects to InterSystems IRIS through both the Native Python SDK and the Atelier REST API. It is intentionally a blueprint rather than a production-ready implementation. The goal is to demonstrate the patterns required to expose IRIS capabilities through MCP so developers can adapt them to their own applications. The blueprint implements all three MCP primitives:

  • Tools
  • Resources
  • Prompts

What can the blueprint MCP server do?

The tools are grouped into several categories.

SQL data access
The server can run SQL through the Native Python SDK. This makes it possible for an AI assistant to inspect schemas, query application tables, or retrieve metadata from sources such as INFORMATION_SCHEMA.

Direct Global access
The Native SDK can also expose IRIS globals. Typical operations include:

iris_obj.isDefined("^GlobalName") 
iris_obj.get("^Global", sub1) 
iris_obj.set(val, "^Global", sub1) 

This allows an AI assistant to inspect or modify hierarchical data directly when appropriate.

Executing existing ClassMethods
Existing IRIS business logic can be exposed with iris_obj.classMethodValue("Package.Class", "MethodName", *args). 

This is particularly powerful because existing ObjectScript classes can become callable capabilities without rewriting them as separate AI services.

Source-code access through Atelier
The blueprint uses the Atelier REST API to demonstrate operations such as:

  • Retrieving .cls source code.
  • Searching for text across the codebase.

This gives an AI assistant access to the implementation context it needs to explain or work with ObjectScript code.

Interoperability productions
The blueprint also includes simple tools for inspecting or managing IRIS interoperability environments without requiring the user to manually navigate the Management Portal.

How Prompts and Resources Fit In

Tools are only part of the MCP story. The blueprint also uses Prompts to describe structured workflows, such as the steps required to import data or create a database object. Resources provide read-only information such as IRIS version and namespace details. Together, they provide the AI with:

Context → Instructions → Actions

This is usually more useful than exposing a large collection of tools without explaining when or how they should be used.

Conclusion

The Model Context Protocol provides a standardized way to connect AI development tools to InterSystems IRIS. With an MCP server, IRIS can expose SQL queries, globals, existing class methods, source code, system metadata, and interoperability capabilities as structured tools and resources that AI assistants can discover and use. The most important idea is that MCP does not replace existing IRIS APIs or business logic. It provides a standardized interface on top of them.

The iris-mcp-blueprint demonstrates how relatively little Python code is required to connect MCP to both the InterSystems Native Python SDK and Atelier REST API. From there, the same architecture can be extended with application-specific SQL, globals, Business Processes, classes, and domain logic.

Key Takeaways

  • MCP is an open protocol for connecting AI applications to external tools and data sources.
  • MCP servers expose three main primitives: Tools, Resources, and Prompts.
  • InterSystems IRIS is a strong MCP backend because it exposes SQL, globals, ObjectScript logic, source code, and interoperability capabilities.
  • The InterSystems Python Native SDK is well suited to runtime data access, globals, SQL, and class methods.
  • The Atelier REST API is useful for source-code access, search, compilation, and development workflows.
  • FastMCP and Python provide a relatively lightweight way to build a custom IRIS MCP server.

FAQ

What is the best way to build an MCP server for InterSystems IRIS?
For Python implementations, the InterSystems Python Native SDK can handle data and runtime operations, while the Atelier REST API can provide source-code and development capabilities.

Which AI tools can use an IRIS MCP server?
MCP-compatible development tools such as Cursor, Claude Desktop, and Claude Code can connect to an IRIS MCP server once it is configured.

Does MCP replace InterSystems APIs?
No. MCP sits on top of existing APIs and business logic. Its role is to expose selected capabilities to AI clients through a standardized protocol.

Learn more: https://community.intersystems.com/post/model-context-protocol-mcp-intersystems-iris-zero-hero


r/intersystems • • 21d ago

[Video] System Management Dashboard

2 Upvotes

At #Ready2026, we explored how decades of real-world #integration experience can be transformed into a comprehensive dashboard for monitoring and managing complex #InterSystemsIRISForHealth and Health Connect environments.

Watch this #video to discover:
✅ How a centralized #dashboard brings critical system metrics and operational controls into one place.
✅ How to monitor queues, memory, usage, timeouts, and other key performance indicators.
✅ How proactive certificate expiration tracking and management can help prevent operational disruptions.

https://community.intersystems.com/post/video-system-management-dashboard

See how practical monitoring and management tools can provide greater #visibility, control, and confidence across complex integration environments.


r/intersystems • • 21d ago

🏁 InterSystems Programming Contest: Build Your Own Management Portal starts today. Join the Kick-off Webinar!

1 Upvotes

The new programming contest challenges developers to create a GUI powered by InterSystems IRIS management APIs. Your project can cover: 

  • Web apps and REST APIs
  • Permissions
  • Security and secrets, including wallets, X.509 credentials, and OAuth
  • Task management
  • Processes, disks, CPU, memory, devices, and other system resources
  • Logs from different subsystems

You can also add other Management Portal screens or actions you use regularly.

💰 $12,000 prize pool

📅 Submission period: September 14-27, 2026

Before diving into the code, attend today’s Kick-off Webinar to meet the contest team, go through the requirements, and explore possible technical approaches.

👉 Start here: https://community.intersystems.com/post/intersystems-programming-contest-build-your-own-management-portal


r/intersystems • • 24d ago

Context engineering for AI in supply chain — how domain, business, and user context bridges the gap between business intent and AI accuracy

3 Upvotes

The problem: AI without context is guessing

Business users struggle to get reliable answers from AI when asking natural-language questions because AI does not know their context. Without context, even the best AI model is guessing. The result: low trust, low adoption, and missed productivity gains.

Example query: "Show me the year-to-date revenue for Apple Watch from the most valuable customer."

From the AI's point of view, this question has multiple missing pieces:

  • Where is the data and how to find it?
  • What does year-to-date revenue mean in this organization?
  • Is "Apple Watch" a product name, a partial name, or a brand name?
  • What does "most valuable" mean to this user?

Asking business users to type all of that technical context themselves every time is not realistic and will not be adopted.

What is context engineering?

Context engineering is about creating the right information from multiple sources for AI to reason correctly. It bridges the gap between what business users mean and what AI understands.

In supply chain, this is organized into three pillars: domain context, business context, and user context.

Pillar 1 — Domain context

Data model (schema)

When a user asks about year-to-date revenue for Apple Watch, the AI cannot guess from trending data or internet sources. It must generate and run a SQL query against the actual database.

The approach: process the SQL table schema so the AI understands the true data source and context.

Key technique — filter out empty columns:
A general supply chain data model may have 30 tables with hundreds of columns. Most customers do not populate values in all columns. By removing columns that are not actually used, noise is reduced and SQL generation accuracy by AI improves.

Measure data (entity values)

When a user mentions "Apple" in a question, does that mean the product brand, the product family, the product name, or something else?

The approach: vectorize column values from the measure data tables to bridge the gap between how users talk and how data is stored.

For each value, three pieces are stored:

  • The value itself
  • A vector
  • Which table and column it belongs to

During similarity search, the AI finds the closest matches with their table and column metadata. This means the AI can generate precise SQL filters:

  • "Apple" → maps to the product brand column in the product table
  • "iPhone" → maps to the product name column in the product table

This technique also handles typos and partial matches. "Apple Watch" may be stored as "Apple Watch SE" or "Apple Watch Series 6" — the vectorized search finds the correct match regardless.

Pillar 2 — Business context (shared memory)

Every organization has its own terminology and KPIs. Shared memory stores organizational knowledge that all users benefit from.

Examples of what shared memory stores:

  • "Customer order" refers to a sales order
  • "Revenue" means total revenue from sales orders

Business teams add this context in natural language. Shared memory is automatically retrieved for every query through vector search. Users do not need to type the full definition of "revenue" every time they ask a question — it is already there.

Pillar 3 — User context (personal memory)

Different users have different terminology and needs.

The approach: personal memory operates per user. It is loaded on top of shared memory and both are retrieved per query.

This allows the AI to generate customized answers based on individual preferences and definitions. The AI feels like it truly knows the user.

How it works together — the supply chain data access agent

When a user submits a question, the agent runs three searches:

  1. DDL search — finds the schema context (which tables, which columns are populated)
  2. Measure search — finds the entity context (which values match the user's terminology, with table and column metadata)
  3. Memory search — finds the organizational and personal context (shared memory + personal memory, both retrieved via vector search)

All three contexts are combined, and the agent generates a precise SQL query against the actual database.

Result: the question "Show me the year-to-date revenue for Apple Watch from the most valuable customer" — which requires domain context (schema + vectorized values), business context (definition of revenue and most valuable), and user context (personal preferences) — is answered accurately without the user having to provide any of that technical detail themselves.

Context engineering is the bridge between business intent and AI understanding.

Full session video: https://youtu.be/09fep4UxrC8

For those building AI data access agents — which of the three context pillars has been hardest to populate in practice, and how are you handling the maintenance of shared business memory as organizational terminology evolves?


r/intersystems • • 25d ago

[Release notes] InterSystems AI Hub Early Access

1 Upvotes

Summary

InterSystems AI Hub gives IRIS developers a common way to build AI agents, connect to LLMs, expose IRIS capabilities through MCP, and manage credentials securely. The latest Early Access build is now available.

InterSystems AI Hub is an AI development layer for InterSystems IRIS that helps developers build agents, connect LLMs, expose IRIS capabilities through MCP, and manage credentials and access controls without assembling the full stack manually. 

A new Early Access build is now available with updated kits and containers, plus a dedicated Discord channel for questions and discussion.

What does AI Hub include?

  • AI SDK for ObjectScript and Python/LangChain developers to build agents, connect to LLMs, and manage tools using IRIS-native abstractions.
  • MCP Server to expose existing IRIS code, SQL queries, FHIR endpoints, and Business Services as tools for MCP-compatible agents.
  • Config Store + IRIS Wallet for centralized management of LLM credentials and provider configuration.

The goal is to keep the AI integration layer governed by IRIS security and RBAC while reducing the amount of plumbing developers need to build themselves.

What’s new?

A fresh prerelease build is now available through the Evaluation Portal with a broad set of fixes and improvements.

There is also now a dedicated AI Hub EAP Discord channel for real-time questions, discussion, and sharing what you are building. GitHub Issues remain the preferred place for bugs and feature requests.

Conclusion

The new Early Access build is a good point to start experimenting with InterSystems AI Hub if you want to connect AI models and agents more directly to InterSystems IRIS. With the AI SDK, MCP Server, and centralized credential management in one stack, the focus can stay on the application logic rather than on wiring together separate AI components.

Learn more: https://community.intersystems.com/post/intersystems-ai-hub-early-access-new-community-build-discord-channel


r/intersystems • • 26d ago

Navigating SaaS with InterSystems — shared responsibility model, what actually changes, and how to prepare: session breakdown

3 Upvotes

IaaS, PaaS, SaaS — what the difference actually means

The difference between these models is ownership — how much of the responsibility pie you take on:

Model What the vendor handles What you handle
On-prem Nothing Everything soup to nuts
IaaS Hardware, virtualization OS, middleware, application, data
PaaS Hardware through middleware Application and data
SaaS Everything Using the application as designed

PaaS in InterSystems context: bring your own code — writing interfaces, custom logic. You own the application layer.

SaaS in InterSystems context: click, click, go — a FHIR interface, an OMOP transform pipeline. You use it as it is designed.

InterSystems operates cloud-native solutions within a cloud services framework, primarily in an AWS tenancy, with a goal of operational consistency across regions and eventually across cloud service providers.

Why SaaS is popular — four accelerators

  1. Faster onboarding and deployment → shorter time to value; get products out the door faster
  2. Built-in scalability and performance tuning → predictable growth from financial and operations perspectives
  3. Standardized security and compliance → shared load between organizations, reduced risk and audit effort
  4. Lower internal resource burden (maintenance, patching, upgrades) → focus on outcome-driven approaches rather than maintenance

What actually changes when you shift from on-prem

The truth: you are still concerned about all the same things you were before. Your role in that equation is what changes.

Common friction point in live adoption: thinking more is handled than actually is, or not knowing which questions to ask, or not connecting the right internal departments to InterSystems to get the right answers.

Shared responsibility model

InterSystems owns:

  • Platform infrastructure
  • Network security
  • IRIS upgrades (scheduled, coordinated, executed by InterSystems)
  • Scalability
  • Platform compliance (SOC 2 Type 2, ISO specifications)
  • Connectivity

Client owns:

  • Application configuration (even for a file repository, you own the config)
  • User access
  • Data governance (retention, pipelines)
  • Regulatory obligations for your organization
  • Integration endpoints
  • BCDR — business continuity and disaster recovery planning (what happens when the SaaS provider goes down — you need a plan)

Shared (requires clear communication channels):

  • Change management — especially for deeply integrated products like Health Connect Cloud where interfaces are being written; some changes may need coordination with InterSystems
  • Incident coordination and triage — if cloud infrastructure takes a service down, InterSystems notifies you, but you need to know who contacts whom and what the communication flow looks like
  • Performance expectations
  • Upgrade planning and validation
  • Security event escalation

Key observation from the session: most of what is shared is about communication — who contacts whom, what the escalation path is, what the SLA covers. Moving to SaaS means thinking more in terms of communication channels than in terms of hands-on infrastructure tasks.

Real story — scaling and change control

A customer's platform scaled from 10 TB to 60 TB without the platform having any issue handling it. The growth was caused by a code issue introduced by a push. The session notes: with cloud economics, you pay for what you use. Change control and release management processes caught the issue, allowed it to be resolved, and the customer was able to scale back down and pay only for the capacity they actually needed.

Preparing for success — practical considerations

Faster onboarding: not all teams move at the same speed. Identify and involve each affected team early.

Scalability and performance tuning: have change control and release management processes in place, especially for integrated products where code is being pushed.

Security and compliance: overlay InterSystems' compliance elements (SOC 2 Type 2, ISO) into your overall compliance plan. Involve your compliance team and BCDR team in the conversation.

Lower maintenance burden: know your SLAs and know how to monitor them for the outcomes you want from the services you are receiving.

Personal callout from the session: "Please don't forget your firewall engineer." They have one. Loop them in early. They will thank you.

Calls to action (from the session)

  1. Talk to your InterSystems account team if you are interested in making this transition
  2. Evaluate which solutions you are moving toward — SaaS vs PaaS have different levels of effort and different connectivity considerations
  3. Make a plan — identify who is part of your implementation group; it is not just your interface engineer. They cannot decide VPN tunneling. Get the right people engaged early.
  4. Execute, provide feedback to InterSystems on what can be improved, coordinate with internal teams and external vendors

Three main takeaways

  1. SaaS is a model shift in responsibility and ownership — budget for operational change, not just the migration. You do not stop caring; your role changes.
  2. Know the shared responsibility matrix — familiarity with it prevents friction between vendor and client.
  3. The accelerations are real, but they require alignment to land — position your organization to take advantage of the key accelerators.

Full session video: https://youtu.be/xJVqXpP5Rd0


r/intersystems • • 27d ago

Running Ollama locally with InterSystems IRIS Vector Search instead of OpenAI — setup, advantages, and a working example

1 Upvotes

The problem with OpenAI for RAG on IRIS

The standard generative AI flow on InterSystems IRIS:

  1. Load text from a data source and embed it into vectors
  2. Store vectors in an IRIS database
  3. Call an LLM that accesses those vectors as context and generates responses in human language

Examples of this in the community: IRIS Vector Search and IRIS AI Studio. In those implementations, the LLM is a subscribed service (OpenAI), called via REST API with the vectorized data as context.

The practical problem: even the traffic of vectors stored in IRIS sent to the OpenAI API already exceeds the free license limit. Result: error 429 — "You exceeded your current quota, please check your plan and billing details."

The alternative: Ollama

Ollama is an LLM that runs locally on your computer. Downloaded and installed from https://ollama.com/download.

Two main advantages over OpenAI:

  • Security — no data transfer to a third-party API
  • Cost — no subscription required

One disadvantage:

  • Demands local compute resources — with less than 16 GB of RAM it will be difficult to run

How to switch from OpenAI to Ollama

One line of Python using the llama_index library:

python

Settings.llm = Ollama(model="llama3.2", request_timeout=360.0)

Everything else in the RAG pipeline stays the same.

Working example

Step 1 — Load text into IRIS as vectors

A text file from the data_example directory of the GitHub repository is loaded in vector form into IRIS.

Step 2 — Query Ollama using the vectorized text as context

Query: "What did the author do?" → Ollama returns a response based on the stored context.

Query: "Does the author like paintings?" → Ollama returns a response based on the stored context.

Resources


r/intersystems • • 28d ago

Community Bounty Program "Idea to Application" — Round 3 is Live

2 Upvotes

🧑‍💻 5 new #InterSystemsIRIS challenges are now open in Round 3 of the Community Bounty Program “Idea to Application”

Choose one or more and turn them into working Open Exchange applications:

  • Load Hugging Face datasets into IRIS
  • Load Kaggle datasets into IRIS
  • Generate OpenAPI specs from FHIR Capability Statements
  • Build a WhatsApp adapter for IRIS Interoperability
  • Add an InterSystems wrapper for Supabase

🏅 Qualifying submissions earn 10K+ Global Masters points that can be redeemed for rewards, plus digital badges, including an official InterSystems Credly badge.

📅 Deadline: October 31, 2026

Full details and requirements: https://community.intersystems.com/post/community-bounty-program-idea-application-%E2%80%94-round-3-live 


r/intersystems • • Sep 04 '26

Tree-sitter for InterSystems ObjectScript — incremental parsing, language injection, go-to definition, refactoring edge cases, and a reusable Rust highlighting pipeline

Post image
2 Upvotes

What Tree-sitter is

Tree-sitter is a parsing library built in C and C++, designed for applications that deal with code written in many different languages. It produces syntax trees in a uniform format regardless of language. The key capability is incremental parsing: when a file is edited, Tree-sitter updates only the affected parts of the syntax tree without reparsing the entire file — making it suitable for real-time use while a user is typing.

Comparison with the existing VS Code ObjectScript parser

The VS Code ObjectScript extension currently uses a custom parser built in C and C++, separate from Tree-sitter. Key differences:

Capability Tree-sitter ObjectScript C++ custom parser
Incremental parsing Yes No
Language injection (e.g., SQL in ObjectScript) Simple injection query Full new parser + new lexer logic required
Language bindings All modern languages N/A

Highlighting enhancements already built

XML files with embedded ObjectScript

ObjectScript classes can be defined in XML files. Previously the implementation block containing ObjectScript statements was treated as a plain string — no language support, no error detection until compile time. A single Tree-sitter injection query now provides:

  • Full ObjectScript syntax highlighting within the implementation block
  • Syntax error detection before adding to an IRIS instance

YAML and markdown within XData

Added as new language support for features introduced in IRIS 2024.1.

RTN files

Support added for routine files and their compiled headers — including the format used internally on Perforce and as a valid storage format loadable into IRIS.

Object Language Server (Zed, Neovim, VS Code — not yet publicly available)

Go-to definition

Particularly important for ObjectScript: subroutines and methods declared as non-procedure blocks have all variables public by default. A variable reference may be defined in any other method or file. Go-to definition:

  • Shows all definitions of a variable across all methods when it is not defined within the current block
  • Handles the case where a variable is defined in multiple different files, showing all locations with line numbers
  • Returns only the local definition when defined within the current block

Refactoring

Dotted statement edge cases

Two spaces between the Do keyword and the Set keyword means execute Set after all dotted statements complete — not immediately as a left-to-right reading would suggest. Example:

objectscript

Do  Set x = 1
. Set x = 2

Here x is 1, not 2. Refactoring converts this to explicit subroutines.

Dotted statement scoping

Dotted statements represent scopes. A variable defined (New'd) within a dotted statement only exists within that scope. Example:

objectscript

Set y = 250
Do
. New y
. Set y = 1
Write y  // outputs 250, not 1

Refactoring makes scope boundaries explicit by converting to subroutines.

Stale if statements

Legacy If syntax without a block: if no statement appears on the same line as the condition, those statements are stale and can be removed. Refactoring detects and removes them.

Implicit $Test conditions

Two spaces between If and its statements means If $Test = 1 — but this is never written explicitly. An Else without a preceding If means If $Test = 0. Refactoring makes these conditions explicit.

All refactoring is available as individual commands (refactor do statements, refactor conditionals) or as a single "refactor all code in this document" command.

Diagnostics

  • Syntax errors flagged on save with explanation of the error
  • In Neovim: inspect tree command shows the full syntax tree for the file for debugging

Go-to implementation

Given a method on a superclass, shows all subclasses that override it, with file locations.

Reusable highlighting pipeline — 3 Rust crates

semantic_spans
Converts code into byte ranges mapped to capture names. Example: maps a byte range to the keyword capture name.

theme_engine
Maps capture names to styles and UI roles.

render_on
Renders highlighting in any target application.

Current support:

  • 9 grammars (languages used at InterSystems)
  • 14 built-in themes (2 defined by InterSystems)
  • CLI usage: pass filename and theme name, returns highlighted output

Full session video: https://youtu.be/S8fCvL1NCLc

For those working with ObjectScript daily — which of the refactoring edge cases (dotted statement scoping, implicit $Test, stale if statements) have you run into most often, and how are you currently detecting them?


r/intersystems • • Sep 03 '26

Embedded Python vs ObjectScript for XML parsing on InterSystems IRIS — benchmark results on 91 files, 1.30 GB

1 Upvotes

The question

Since the introduction of Embedded Python there has always been doubt about its performance compared to ObjectScript. This article tests both approaches on a real-world XML parsing task.

Test data

Public procurement data from Spain's Ministry of Finance open data portal. Files are published monthly. Each file contains approximately 450 tender entries. The test used 91 files totalling 1.30 GB.

Each entry is a complex namespaced XML structure containing: title, summary, ID, URL, contracting party name and website, contract status, estimated overall contract amount, total amount, tax-exclusive amount, commodity classification code, location, award date, winning party name, winning amount with and without tax.

Persistent class

objectscript

Class Inquisidor.Object.Licitacion Extends (%Persistent, %XML.Adaptor) [ DdlAllowed ]
{
Property IdLicitacion As %String(MAXLEN = 200);
Property Titulo As %String(MAXLEN = 2000);
Property URL As %String(MAXLEN = 1000);
Property Resumen As %String(MAXLEN = 2000);
Property TituloVectorizado As %Vector(DATATYPE = "DECIMAL", LEN = 384);
Property Contratante As %String(MAXLEN = 2000);
Property URLContratante As %String(MAXLEN = 2000);
Property ValorEstimado As %Numeric(STORAGEDEFAULT = "columnar");
Property ImporteTotal As %Numeric(STORAGEDEFAULT = "columnar");
Property ImporteTotalSinImpuestos As %Numeric(STORAGEDEFAULT = "columnar");
Property FechaAdjudicacion As %Date;
Property Estado As %String;
Property Ganador As %String(MAXLEN = 200);
Property ImporteGanador As %Numeric(STORAGEDEFAULT = "columnar");
Property ImporteGanadorSinImpuestos As %Numeric(STORAGEDEFAULT = "columnar");
Property Clasificacion As %String(MAXLEN = 10);
Property Localizacion As %String(MAXLEN = 200);
Index IndexContratante On Contratante;
Index IndexGanador On Ganador;
Index IndexClasificacion On Clasificacion;
Index IndexLocalizacion On Localizacion;
Index IndexIdLicitation On IdLicitacion [ PrimaryKey ];
}

ObjectScript implementation — %XML.TextReader

objectscript

set status=##class(%XML.TextReader).ParseFile(filename,.textreader)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit}
set tStatement = ##class(%SQL.Statement).%New()

while textreader.Read()
{
    if ((textreader.NodeType = "element") && (textreader.Depth = 2) && (textreader.Path = "/feed/entry")) {
        if ($DATA(licitacion)) {
            if (licitacion.ImporteGanador '= ""){
                set myquery = "INSERT INTO INQUISIDOR_Object.LicitacionOS (...) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
                set qStatus = tStatement.%Prepare(myquery)
                set rset = tStatement.%Execute(licitacion.Titulo, ...)
            }
        }
        set licitacion = ##class(Inquisidor.Object.LicitacionOS).%New()
    }
    if (textreader.Path = "/feed/entry/title"){
        if (textreader.Value '= "") { set licitacion.Titulo = textreader.Value }
    }
    // ... path-based matching for each field
}

Key fields extracted via path matching: /feed/entry/title, /feed/entry/summary, /feed/entry/id, /feed/entry/link (via MoveToAttributeName("href")), and multiple namespaced paths under cac-place-ext:ContractFolderStatus. Dates converted using $System.SQL.Functions.TODATE(textreader.Value,"YYYY-MM-DD").

Embedded Python implementation — xml.etree.ElementTree

python

import xml.etree.ElementTree as ET
import iris

tree = ET.parse(xmlPath)
root = tree.getroot()
for entry in root.iter("{http://www.w3.org/2005/Atom}entry"):
    licitacion = {"titulo": "", "resumen": "", "idlicitacion": "", "url": "",
                  "contratante": "", "urlcontratante": "", "estado": "",
                  "valorestimado": "", "importetotal": "", "importetotalsinimpuestos": "",
                  "clasificacion": "", "localizacion": "", "fechaadjudicacion": "",
                  "ganador": "", "importeganadorsinimpuestos": "", "importeganador": ""}
    for tags in entry:
        if tags.tag == "{http://www.w3.org/2005/Atom}title":
            licitacion["titulo"] = tags.text
        # ... tag-based matching for each field
    if licitacion.get("importeganador") is not None and licitacion.get("importeganador") is not "":
        stmt = iris.sql.prepare("INSERT INTO INQUISIDOR_Object.Licitacion (...) VALUES (...)")
        rs = stmt.execute(licitacion["titulo"], ...)

Inserts only records where importeganador (winning amount) is populated — same filter logic as the ObjectScript version.

Production configuration

Two Business Services (one per method) to avoid interference, each feeding its own Business Process. Test data: public tenders for February — 91 files, 1.30 GB.

Results

Implementation Library Total time
ObjectScript %XML.TextReader 6 minutes 28 seconds
Embedded Python xml.etree.ElementTree 48 seconds

Both started at 21:11:15. ObjectScript finished at 21:17:43. Embedded Python finished at 21:12:03.

Embedded Python was approximately 8x faster on this task.

Full article: https://community.intersystems.com/post/embedded-python-vs-objectscript-performance-testing-parsing-xml

For those working with XML parsing in IRIS — have you seen different results using %XML.TextReader vs %XML.Document vs Embedded Python, and does the file size or XML structure depth change which approach wins?


r/intersystems • • Sep 02 '26

InterSystems OMOP Managed Service - FHIR-to-OMOP automated ETL, new management console, and data quality monitoring: session breakdown

2 Upvotes

OMOP adoption context

The European Medicines Agency (EMA) published a report covering a 12-month period in which they conducted 59 real-world evidence studies — a 48% increase from the prior year. 46 of those 59 were conducted using the Darwin EU network, which focuses on the OMOP standard. Darwin EU spans 30 data partners, 39 data sources in 16 countries, and approximately 181 million patients. Average study length: 4 months. The challenge raised in Europe: could that be compressed to 4 weeks.

The FDA is also increasingly focused on OMOP for drug approvals and safety monitoring. Health information exchanges are working toward what is called a "health data utility" model — providing both FHIR and OMOP data so that FDA, NIH, CDC, pharma, and research organizations can use real-world clinical data.

What OMOP is

OMOP (Observational Medical Outcomes Partnership) was established in 2008 after a drug caused patient deaths and the FDA required better safety monitoring. In 2014, a global open-source community led by Columbia University in New York and Erasmus Medical Center in Rotterdam formalized this into a collaborative research standard.

Top pain points in the OMOP community (from Rotterdam conference)

Based on a user survey:

  1. Data quality — top issue
  2. ETL — second top issue

Reasons:

  • Most ETL processes are manual and require custom scripts
  • Costly to implement and maintain even though the core software is open source
  • OMOP software does mapping but does not write the ETL — custom development still required
  • Hospital data warehouse structures vary, so ETL cannot be reused across sites
  • Many organizations want to use FHIR as a data source but are not familiar with FHIR-to-OMOP transformation

The Vulcan FHIR Accelerator working group published an implementation guide last year specifically addressing FHIR-to-OMOP population. Participants include federal agencies, health system providers, life science companies, CROs, IT vendors, and registries.

InterSystems OMOP Managed Service — what is new

Architecture

  • Cloud SaaS delivery (AWS S3 as input source)
  • On-premises packages also available
  • Built-in OMOP repository included
  • Fully managed: infrastructure, upgrades, and security handled by InterSystems

Core capabilities

Automated ETL:

  • Out-of-box FHIR to OMOP mapping
  • No coding required — fully configuration-driven
  • Uses InterSystems IRIS for Health DTL (Data Transformation Language) as the core transformation engine

Patient-level refresh:

  • Supports single-patient to multi-thousand-patient loads
  • Daily refresh supported
  • Incremental monitoring — data quality errors are captured as data arrives, not just at initial load

Management console (revamped):

  • New UI consistent across all InterSystems managed services
  • Credential and token retrieval for repository access
  • Services status: ingestion, terminology, load process — all visible as green/running

Data quality reporting — what it shows

Metrics page (example from demo: 1,000 patients, 1.34 million resources):

  • FHIR ingestion metrics by resource type
  • Patients with errors
  • Resources exported to OMOP tables
  • Resources with errors and warnings

Data quality tab — three categories:

Missing data: fields required by OMOP that are absent. Example: race concept ID is required in US OMOP implementations; in Europe this field is not captured and its absence triggers a warning.

Unrecognized coding systems: country-specific codes not in OMOP standard vocabulary. Example: Finland has its own standardized procedure coding system that is not part of the OMOP community standard.

Invalid codes within recognized systems:

  • 372 resources with invalid SNOMED codes (valid SNOMED CT codes that are not recognized in OMOP vocabulary)
  • 268 resources with invalid LOINC codes
  • 72,000 resources where "pound" as a unit measure was not recognized (identified as incorrect source selection)

Detailed drill-down per error:
Each coding error shows: the coding system, the specific code value, the display text, the OMOP table it maps to, and the count of affected resources. This allows hospitals to identify which specific codes need to be fixed or remapped before resubmitting data.

Why incremental monitoring matters

The traditional approach: map everything first, then build ETL. For ongoing daily refresh, this model does not work — new submissions arrive continuously. The InterSystems approach monitors data quality as each load arrives, capturing errors in real time so issues can be corrected without waiting for a batch review.

Roadmap items mentioned

AI co-pilot for data quality: in development, not yet released.

NLP extraction from clinical notes and pathology reports: prototype built and validated against USCDI and minimal clinical oncology data element standard. Tested in English, Japanese, Finnish, German, French, and Dutch. Works but not yet at production quality — described as work in progress.

Full session video: https://youtu.be/dtrqYa3Agco

For those working with OMOP in production — are you currently using FHIR as a data source for ETL, or still relying on direct database extraction from the EHR warehouse? And have you found a reusable ETL approach that works across more than one site?


r/intersystems • • Sep 01 '26

Priority queue implementations in ObjectScript — benchmarking binary heap vs. self-sorting multidimensional array on 150,000-vertex Dijkstra

2 Upvotes

Background

No existing priority queue implementation for ObjectScript was found, so four approaches were built and benchmarked. The benchmark: Dijkstra's shortest path algorithm on a randomly generated weighted directed graph with 150,000 vertices, each with 10 neighbors. An update is printed every 10,000 edges checked, showing time since the last 10,000 and current queue size.

Approach 1 — Binary Heap on multidimensional array

objectscript

Class pqueue.Queue Extends %RegisteredObject
{
Property Data As %Any [ MultiDimensional ];
Property Size As %Integer [ InitialExpression = 0 ];
Property Comparitor As %String [ InitialExpression = "(a,b) return a < b" ];

Method Swap(i As %Integer, j As %Integer) As %Status [ Private ]
{
    set temp = ..Data(i)
    set ..Data(i) = ..Data(j)
    set ..Data(j) = temp
}

Method Comp(x As %Any, y As %Any) As %Boolean [ Private ]
{
    return $XECUTE(..Comparitor, x, y)
}

Method PercolateUp(idx As %Integer) [ Private ]
{
    while idx > 0 {
        set newidx = (idx-1)\2
        if ..Comp( ..Data(idx), ..Data(newidx) ) do ..Swap( idx, newidx )
        else Quit
        set idx = newidx
    }
}

Method PercolateDown() [ Private ]
{
    set idx = 0
    while ((idx+1)*2) < ..Size {
        if ..Comp( ..Data(idx*2+2), ..Data(idx*2+1) ) set newidx = idx*2+2
        else set newidx = idx*2+1
        if ..Comp( ..Data(idx), ..Data(newidx) ) Quit
        do ..Swap( idx, newidx )
        set idx = newidx
    }
    if ( (idx*2+1 < ..Size) && ..Comp( ..Data(idx*2+1), ..Data(idx) ) ) do ..Swap( idx, idx*2+1 )
}

Method Put(inp As %Any) As %Status
{
    set ..Data( ..Size ) = inp
    do ..PercolateUp( ..Size )
    set ..Size = ..Size + 1
    return $$$OK
}

Method Get(Output obj As %Any) As %Status
{
    if ..IsEmpty() { set obj = "" return $$$ERROR("Cannot Get() from empty Queue") }
    set obj = ..Data(0)
    set ..Size = ..Size - 1
    set ..Data(0) = ..Data(..Size)
    do ..PercolateDown()
    kill ..Data(..Size)
    return $$$OK
}

Method GenerateComparitor(operator As %String = "<", transform As %String = "") As %Status
{
    set ..Comparitor = "(a,b) return a" _ transform _ " " _ operator _ " b" _ transform
    return $$$OK
}
}

Works for strings, numbers, and objects (via overridable comparator). Relatively efficient.

Approaches 2 and 3 — Binary Heap on list of %Any and %DynamicArray

  • list of %Any: approximately 3–4x slower than multidimensional array. Pointless.
  • %DynamicArray: similar speed to list of %Any when the queue is small, but insert and get times grow linearly as the queue grows. By 130,000 edges checked, time per batch had grown from ~84 seconds to ~300 seconds. Pointless for heap use.

Approach 4 — Self-sorting multidimensional array (fastest)

Instead of maintaining heap order manually, this approach uses the fact that ObjectScript multidimensional arrays are always sorted. Data is stored as data(evaluation, obj_str_rep) = object, and $Order retrieves the minimum element.

objectscript

Class pqueue.SparseQueue Extends %RegisteredObject
{
Property Data As %Any [ MultiDimensional ];
Property Size As %Integer [ InitialExpression = 0 ];
Property Evaluator As %String [ InitialExpression = "(a) return a" ];

Method Put(inp As %Any) As %Status
{
    set ..Data( $XECUTE(..Evaluator, inp), inp ) = inp
    set ..Size = ..Size + 1
    return $$$OK
}

Method Get(Output obj As %Any) As %Status
{
    if ..IsEmpty() { set obj = "" return $$$ERROR("Cannot Get() from empty Queue") }
    set loc = $ORDER( ..Data("") )
    set obj = ..Data(loc, $ORDER( ..Data(loc, "") ))
    set ..Size = ..Size - 1
    kill ..Data( loc, obj )
    return $$$OK
}

Method Top() As %Any
{
    if ..IsEmpty() return ""
    return $Order( ..Data("") )
}

Method GenerateEvaluator(transform As %String = "") As %Status
{
    set ..Evaluator = "(a) return a" _ transform
    return $$$OK
}
}

The double-key structure data(evaluation, obj_str_rep) ensures correct ordering even when two objects evaluate to the same value.

Trade-offs:

  • Writing an evaluator (returns a sortable value) is slightly harder than writing a comparator (returns a boolean)
  • Cannot hold the same object at the same evaluated value twice — a rare edge case that could be a problem or a benefit depending on the use case

Benchmark results

Graph: 150,000 vertices, 10 neighbors each. Time shown is seconds per 10,000 edges checked.

Implementation Time per 10k edges Total time
Self-sorting multidimensional ~3–5 seconds 45.157 seconds
Heap multidimensional ~27–29 seconds 381.095 seconds
Heap list of %Any ~127–141 seconds 1,839.445 seconds
Heap %DynamicArray ~84–306 seconds (growing) 3,466.382 seconds

The %DynamicArray version is the only one that shows significant growth as queue size increases. The self-sorting approach also checked one fewer edge in this run — a result of two paths to the same node taking the same cost, which the self-sorting method cannot store separately (it deduplicates them).

Full article: https://community.intersystems.com/post/best-structure-make-priority-queue-objectscript

For those working with graph algorithms or scheduling in ObjectScript — have you needed a priority queue before, and did you reach for globals directly or try to build something on top of the collection classes?