Skip to main content

Build a Mainframe AI Assistant in OMVS With Amazon Bedrock

Sudarshan Srivathsav, staff software engineer at Symetra, shares a step-by-step guide for developers using Python and ZOAU

Imagine asking, “What does this JCL do?” at an OMVS prompt and getting an answer based on the actual member you chose. In this guide, a Python program running on z/OS reads an approved dataset with ZOAU and asks Claude through Amazon Bedrock to explain it. The same assistant can inspect COBOL or other text members. You can use a coding assistant to create or adapt the Python; you do not need to memorize the Bedrock event format first.

Work through the checks in order. First, prove that Python can reach the model. Next, prove that Python can read a test member. Only then, join the two. All paths, account settings and data set names in this guide are placeholders; use data you are allowed to send to the selected AWS service.

The Tools You Will Use

PartPlain-language job
OMVSThe z/OS UNIX shell where you type the commands
ZOAUIBM Python functions that list and read MVS datasets
Boto3 and BedrockThe Python AWS client and hosted model service
Local assistantThe program that checks a requested read and asks for approval

The assistant has two read-only abilities: list the members of one named PDS or PDSE, and read a limited number of lines from an exact dataset or member. A model can request one of these actions; your Python program decides whether it happens.  

Before You Begin

You need an OMVS user with access to a test data set, Python with boto3 and ZOAU Python bindings, HTTPS access to the Bedrock Runtime endpoint and an AWS identity permitted to invoke a suitable model. An AWS administrator may have to arrange the model and permissions; a z/OS administrator may have to arrange ZOAU, network trust, and dataset access. These are separate permissions.

You will fill in:  an AWS Region, a model or inference profile ID, the location of a trusted PEM file if your network requires one and a data set name such as DEMO.USER.JCL(SAMPLE). A PEM file is a list of certificates used to verify the HTTPS connection; it does not contain your AWS key.

Step 1:  Check Python on OMVS

At the OMVS prompt, type the command below. It imports the AWS library and the IBM dataset library; it does not call AWS or read a dataset.

python3 -c 'import sys, boto3, botocore; from zoautil_py import datasets; print("Python", sys.version.split()[0], "Boto3", boto3.__version__, "ZOAU import OK")'

Expect:  Python and Boto3 version numbers, followed by ZOAU import OK.

If it fails:  Ask the local z/OS Python or ZOAU owner for the installed paths and required ZOAU_HOME, PATH, LIBPATH and possibly PYTHONPATH values. A successful import does not yet prove data set access.

Step 2:  Record Your Bedrock Settings in AWS

In the AWS console, open Amazon Bedrock in the Region from which your OMVS program will connect. In the model catalog, select a Claude model that supports the ConverseStream API and tool use. Copy the invocation ID shown for that model or inference profile. An inference profile is an AWS routing name for model requests. For example, a global Claude profile may start with global. Use the exact ID available to your account. Check where a global or cross-Region profile may process data before choosing it. Record the AWS Region and model ID together.

Expect:  Region such as us-west-2 and a complete model or profile ID. You will put both in a shell file in Step 5.

If unsure:  Send the AWS owner this request: “Please confirm a Claude ConverseStream and tool-use model ID in our Bedrock Region, complete any first-use steps, and tell me whether the ID is a foundation model or an inference profile.”

Step 3:  Give the Caller Permission to Invoke the Model

The AWS identity used by Python needs bedrock:InvokeModelWithResponseStream. If the model ID is an inference profile, its permissions can also need the profile and the underlying model resources in destination Regions. Have the AWS administrator grant only the intended resources using the current Bedrock policy guidance; this is an AWS permission, not a z/OS dataset permission.

Use the organization’s approved short-lived credentials or role-based approach for deployment. For a first test with an existing IAM access key, Boto3 can read a local shared credentials file. A long-lived access key has an access key ID and secret key; AWS_SESSION_TOKEN is used for temporary credentials and is not required for that key pair. Never paste real secrets into an AI prompt, example document or source repository.

Expect:  Your AWS owner can identify which AWS identity will make the call and which model ID it can invoke.

Step 4: Check the Network and Trusted Certificates

OMVS must resolve and reach the Bedrock Runtime HTTPS endpoint for your Region. A company network may route HTTPS through a proxy that uses an internal certificate authority. If so, ask the network team for the PEM bundle used to verify that certificate and note its full OMVS path. If the ordinary public trust store already verifies the connection, the extra AWS_CA_BUNDLE setting is unnecessary. Keep HTTPS verification enabled.

Expect:  A confirmed HTTPS route and, if required, a readable PEM file path. A certificate error later means this trust path needs attention; it does not mean the AWS key is invalid.

Step 5  Create a Small OMVS Environment File

If you use the shared credentials file, create it with your real key values locally. The text below is a template: Replace the words in CAPITALS and do not share the resulting file. If your organization already provides a working AWS profile or credentials provider; keep that arrangement and skip creating a new credentials file.

umask 077
mkdir -p "$HOME/.aws"
vi "$HOME/.aws/credentials"
# In the editor, put these three lines (replace placeholders):
# [default]
# aws_access_key_id = YOUR_ACCESS_KEY_ID
# aws_secret_access_key = YOUR_SECRET_ACCESS_KEY
chmod 600 "$HOME/.aws/credentials"

Create ~/bedrock_env.sh with the settings below. Replace MODEL_ID_FROM_AWS and the Region. Include AWS_CA_BUNDLE only when Step 4 gave you a PEM path; delete that line otherwise. If you use a named credentials profile, add export AWS_PROFILE=”YOUR_PROFILE” and use its section in your existing AWS files. The file contains settings, not key values.

# ~/bedrock_env.sh
export AWS_REGION="us-west-2"
export AWS_DEFAULT_REGION="$AWS_REGION"
export BEDROCK_MODEL_ID="MODEL_ID_FROM_AWS"
export AWS_SHARED_CREDENTIALS_FILE="$HOME/.aws/credentials"
# Optional, only when your network requires this bundle:
export AWS_CA_BUNDLE="/path/to/trusted-ca-bundle.pem"

Load the file into your current OMVS shell with the leading dot. This matters: sh ~/bedrock_env.sh starts another shell and the exports do not remain in your interactive session.

. "$HOME/bedrock_env.sh"
python3 -c 'import os; print(os.getenv("AWS_REGION"), os.getenv("BEDROCK_MODEL_ID"))'

Expect:  Your Region and model ID printed, with no unset values. If you set AWS_CA_BUNDLE, confirm the file exists: Test -f “$AWS_CA_BUNDLE” && echo “PEM found”.

Step 6: Ask Bedrock One Tiny Question

Copy the following into OMVS exactly as a multi-line shell command. This test does not read any mainframe data. It asks for “OK” and prints the model’s stop reason. Constructing a client object alone does not demonstrate that AWS accepted a request.

python3 - <<'PYCODE'
import os
import boto3
 
client = boto3.client("bedrock-runtime", region_name=os.environ["AWS_REGION"])
response = client.converse_stream(
    modelId=os.environ["BEDROCK_MODEL_ID"],
    messages=[{"role": "user", "content": [{"text": "Reply OK"}]}],
    inferenceConfig={"maxTokens": 4096},
)
for event in response["stream"]:
    if "contentBlockDelta" in event:
        print(event["contentBlockDelta"]["delta"].get("text", ""), end="")
    if "messageStop" in event:
        print("\nStop:", event["messageStop"]["stopReason"])
PYCODE

Expect:  Visible response text, such as OK, and Stop: end_turn. That proves your OMVS process reached and invoked Bedrock.

If it fails:  NoCredentialsError: check your credential provider. AccessDeniedException: Ask the AWS owner about model access and streaming invoke permission. Certificate verify failed: Check the trusted PEM. A request that returns Stop: max_tokens ended at the output limit; try a shorter question or a larger budget.

Step 7: Read a Test Dataset Without Bedrock

Use an exact, harmless member you are authorized to read. A PDS or PDSE is a mainframe library; the name in parentheses identifies one member. Replace the fictional name below with yours. This code prints only a line count in OMVS and sends nothing to AWS.

python3 - <<'PYCODE'
from zoautil_py import datasets
member = "DEMO.USER.JCL(SAMPLE)"  # replace with your test member
source = datasets.read(member)
print("Lines read:", len(source.splitlines()))
PYCODE

Expect: A line count greater than zero. If it fails, check the dataset spelling and the OMVS user’s dataset read permission; Bedrock IAM cannot fix a dataset authorization error. [7]

Step 8: Run the Combined Assistant

Copy the accompanying mainframe_bedrock_assistant.py into a directory your OMVS user can read, then load the same environment file and start it. The downloadable companion script should be distributed alongside this Word article. It uses the two read-only ZOAU tools and Bedrock ConverseStream.

. "$HOME/bedrock_env.sh"
python3 mainframe_bedrock_assistant.py

At You >, first ask a general question such as, “What does DISP=SHR mean in JCL?” This requires no dataset. Then ask: “List the members of DEMO.USER.JCL and explain DEMO.USER.JCL(SAMPLE).” Replace the dataset names with your approved test library. The assistant may first ask to list members and then ask to read a member. Each approval prompt displays the exact dataset and line range; type “yes” only if the proposed data may go to Bedrock.

Expect:  A general answer; then prompts beginning ZOAU request; followed by an explanation tied to the actual member. Type “exit” to quit.

Why the approval appears:  Bedrock can suggest a tool call, but the Python code chooses whether to perform the read and return the results. Member names and source lines are sent to Bedrock only after you approve the corresponding request.

Use AI as Your Pair Programmer

You can have a coding assistant explain or adapt the companion script while keeping each change small. Describe the outcome and the constraints, ask it for one change at a time, and test the changed file on a harmless member. The coding assistant that helps write the program and the Claude model called by the running program are two distinct roles.

To understand the code, give your coding assistant this prompt:

Explain mainframe_bedrock_assistant.py in the order it runs.
Define each AWS or z/OS term at first use. Show where it:
(1) calls Bedrock, (2) validates a dataset name,
(3) asks permission, and (4) sends the bounded result back.
Use a small example; do not assume I know Bedrock tool use.

To adapt the script for another read-only resource, use this prompt:

Add one read-only tool to the attached OMVS Python assistant.
First explain the exact input and output contract in plain words.
Require an exact resource name, validate it locally, ask before
sending data to Bedrock, and cap the returned size. Preserve
TLS verification and all existing behavior. Never add an
arbitrary shell command, dataset write, or job submit feature.
Show the smallest code change and one safe test I can run.

For troubleshooting, share a redacted error only: “I ran Step 6. I saw <error message>. Which layer failed, what single check should I run next, and what result should I expect?” Remove access keys, internal hostnames, real dataset contents, and private paths before pasting the error into an outside AI service.

When Something Goes Wrong

What you seeFirst place to look
No module named zoautil_pyZOAU Python installation and OMVS library paths; rerun Step 1.
NoCredentialsErrorCredential provider or ~/.aws/credentials; rerun Step 5.
Certificate verify failedProxy trust and optional AWS_CA_BUNDLE path; revisit Step 4.
AccessDeniedExceptionAWS model access, profile ID, and streaming invoke permission; Steps 2–3.
ZOAU dataset errorExact member name and the z/OS user’s dataset permissions; Step 7.
Little or no visible answerPrint the Bedrock stop reason; narrow the question or adjust maxTokens.

A stream can also stop with max_tokens after giving only part of an answer. For longer source analysis, focus the question and use an explicit output budget such as 8192 if your chosen model supports it. More output consumes more tokens and may cost more. The companion script reports an unusual stop reason instead of presenting a partial answer as complete.

What Happens Behind the Prompt

Suppose you ask, “Explain DEMO.USER.JCL(SAMPLE).” The assistant sends your question and descriptions of its two read tools to Bedrock. Claude may ask for read_dataset with that exact member and a line limit. Python checks the name and bounds, shows you the planned read and waits for “yes.” ZOAU reads the source under your z/OS authority. Python returns selected lines to Bedrock so Claude can explain them. This is called tool use: The model proposes an action, and code you control performs it. [8]

You > Explain DEMO.USER.JCL(SAMPLE).
ZOAU request: read DEMO.USER.JCL(SAMPLE), lines 1 through 100
Send these lines to Bedrock? Type yes: yes
Claude > This job has two steps …

This sample dialogue is illustrative. Before approving, check that the printed name is the member you intended. Any reply other than yes declines that read. If you ask about JCL that sends email, the assistant can describe how it works but has no tool to execute the job or send the email.

You can ask follow-up questions in the same session. Keep them focused: “Which DD statements are input?” or “Which line sets the output class?” Ask the assistant to identify its evidence, then open the actual member to verify important claims. If it says the returned data was truncated, narrow the question or ask for the next range.

Keep the First Version Small

The example reads up to 100 member names and at most 160 source lines per tool request; it limits returned characters and tool-request rounds. The ZOAU read itself may still load the full member into the OMVS process before a range is selected, so test with ordinary source members and plan a record-range read for very large datasets. The model’s interpretation also needs human review: A plausible explanation can still be wrong.

For broader use, agree on allowed dataset prefixes, audit reads, secure the local credentials and select a Bedrock routing option that meets your data location requirements. Keep operator approval until your access policy and data controls justify another workflow. The useful starting point is modest: one working model call, one working dataset read and an assistant that joins them with a visible approval step.

References

AWS model access and first-time Anthropic use

AWS inference profiles

AWS inference profile permissions

Boto3 credential sources

AWS SDK CA bundle setting

Boto3 ConverseStream reference

IBM ZOAU datasets Python API

AWS client-side tool use