Quick Summary — This blog demonstrates how IBM Bob with Premium Package for i (PPi) leveraging the IBM i Developer Mode accelerated the development of a production-ready, real-time MSGW job monitor. From generating DDS and SQLRPGLE to compiling and debugging the application, the entire solution was completed in under an hour — a task that would typically take nearly two days using a traditional manual approach.

The Use Case — MSGW Job Monitoring for L1 Operations

In most IBM i environments, experienced developers can handle MSGW jobs without difficulty. They know how to open WRKACTJOB, filter jobs by status, identify the ones waiting in MSGW, and take the appropriate action. However, production monitoring is increasingly handled by Level 1 (L1) service desk analysts who may have little or no IBM i experience.

When a batch job enters MSGW (Message Wait) status, it has stopped processing and is waiting for a response to a system message. The traditional approach required L1 analysts to search through hundreds of active jobs in WRKACTJOB, identify the jobs in MSGW, determine the reason for the message, and then decide what to do next. For someone without IBM i knowledge, that process is slow, confusing, and prone to mistakes.

The requirement was straightforward: provide a simple screen that displays only the jobs in MSGW and offers clear, labelled actions for each one. Analysts should be able to identify the problem and respond without remembering IBM i commands or navigating multiple green-screen displays.

This is the solution I built using IBM i Developer Mode, enabled through the IBM Bob Premium Package for i (PPi).

Starting with a Simple Prompt

I deliberately kept the initial prompt short. I wanted to see how far IBM Bob could go with only a high-level requirement before I started adding implementation details or constraints.

I didn't provide a field list, mention IBM i SQL Services, describe the subfile layout, or specify any DDS keywords. I simply described the problem I wanted to solve.

Rather than returning a generic response, IBM Bob generated a detailed implementation plan that broke the solution into logical development steps. It identified the major components required to build the application before generating any code.

Bob's Implementation Plan

Before generating any code, IBM Bob returned a structured implementation plan. That was the first thing that caught my attention. Instead of jumping straight into code generation, it outlined the overall design, including:

IBM Bob — implementation plan
IBM Bob — structured plan produced before any code was written

For the data source, IBM Bob selected QSYS2.ACTIVE_JOB_INFO(), an IBM i SQL table function that provides a real-time snapshot of active jobs. It planned to retrieve only jobs in MSGW status by filtering the results with WHERE JOB_STATUS = 'MSGW'.

I had used ACTIVE_JOB_INFO() before, so I immediately recognized the approach. What impressed me was that IBM Bob arrived at the same solution on its own and explained the reasoning behind it. Because the service is SQL-based, there is no need to call CL commands or automate WRKACTJOB. You simply query the service like any other table and retrieve the information you need. For a real-time MSGW monitoring application, it was a logical choice.

For the user interface, IBM Bob proposed a DDS display file with a subfile to display one row for each MSGW job. The design also included a fixed footer on lines 22–23 for the function key legend and a message subfile on line 24 to provide operator feedback. It also mapped seven operator actions to the appropriate CL commands, giving the application the functionality needed for day-to-day production support.

OptionActionCL Command
2Work With JobWRKJOB JOB(...)
3Hold JobHLDJOB JOB(...) DUPJOBOPT(*MSG)
4End — ControlledENDJOB JOB(...) OPTION(*CNTRLD) DELAY(30)
5Display MessagesWRKJOB JOB(...) OPTION(*MSG)
6Release JobRLSJOB JOB(...) DUPJOBOPT(*MSG)
7Display Job LogDSPJOBLOG JOB(...) OUTPUT(*)
8End — ImmediateENDJOB JOB(...) OPTION(*IMMED)

That planning step turned out to be more valuable than I expected. It gave me an opportunity to review the overall approach before any code was generated. If I wanted to use a different data source, change the screen design, or support a different set of actions, that was the right time to make those changes.

IBM i Developer Mode — Skills in Action

One thing I noticed while building the application was how IBM i Developer Mode automatically selected the appropriate IBM i skills based on the task. Rather than relying on general AI knowledge, IBM Bob used specialised IBM i skills that understood IBM i development patterns and platform-specific conventions.

Two IBM i skills were used while building this application.

IBM i Developer Mode — Skills in Action
IBM i Developer Mode — IBM i Skills activating automatically for this project

DDS Display Files Skill (dds-premier-basics / dds-display-file) — When generating the display file, IBM Bob used the DDS Display Files skill. It includes IBM i-specific knowledge that is difficult to find in general programming references, such as the correct use of OVERLAY on a subfile control record, the rule that COLOR applies only to named output fields (not unnamed literals), and how message subfiles are integrated using QMHSNDPM. That knowledge allowed IBM Bob to generate a DDS display file that compiled successfully on the first attempt.

ILE RPG Free-Format Skill (rpg-premier-basics / rpg-fundamentals) — When generating the SQLRPGLE program, IBM Bob automatically switched to the ILE RPG Free-Format skill, specifically the SQLRPGLE sub-skill. It generated IBM i-specific constructs such as SFILE(MSGSFL: WkRRN) for subfile processing, declared the display file with INDDS, and used the correct QCMDEXC prototype. These are the kinds of implementation details that are easy to overlook but are essential for a working IBM i application.

Code Generation

Using IBM i Developer Mode, IBM Bob generated two source members directly on the IBM i system:

The Display File — MSGWDSPF

MSGSFL — subfile record format generated by IBM Bob
MSGSFL — subfile record format, generated using the DDS Display Files Skill

The DDS display file contained five record formats: MSGSFL (subfile), MSGCTL (subfile control), FOOTER (function key legend on lines 22–23), and MSGQSFL and MSGQCTL for the message subfile displayed on line 24.

One implementation detail immediately caught my attention. IBM Bob added a hidden 28-character field SFQJOB to store the fully qualified job name (number/user/name) for each subfile row. I hadn't included that requirement in my prompt, but it turned out to be exactly the right design choice. Commands such as HLDJOB and ENDJOB require the fully qualified job name. By storing it as a hidden subfile field, the RPGLE program can read the value directly from the selected subfile record when the operator presses Enter. There is no need to reconstruct the job name from separate fields, perform string manipulation, or query the data again. The required value is already available.

MSGCTL — job count field with conditional COLOR keyword
MSGCTL — CTJOBCNT defined as a named output field so COLOR(GRN/YLW) could be applied

Another nice touch was the job count indicator. IBM Bob displayed the count in green when MSGW jobs were present and yellow when no jobs were found. To support that, it correctly defined CTJOBCNT as a named output field, because the COLOR keyword in DDS applies only to named output fields — not to unnamed constants.

The RPGLE Program — MSGWMON

MSGWMON — control options and file declaration
MSGWMON — DCL-F with SFILE(MSGSFL: WkRRN) and INDDS, generated by the ILE RPG Free Format Skill

One of the first things I noticed in the generated RPGLE program was the file declaration: SFILE(MSGSFL: WkRRN). This keyword is essential for subfile processing. Without it, the compiler does not recognise MSGSFL as a subfile format, and operations such as READC, WRITE, and UPDATE on the subfile fail. The ILE RPG Free-Format Skill generated the declaration correctly on the first attempt.

MSGWMON — querying QSYS2.ACTIVE_JOB_INFO() IBM i SQL Service
MSGWMON — using the QSYS2.ACTIVE_JOB_INFO() IBM i SQL Service to retrieve live job data

For retrieving the job information, IBM Bob chose QSYS2.ACTIVE_JOB_INFO(), which is the IBM i SQL Service designed to provide a real-time view of active jobs. Because it is an SQL service, there is no need to call CL commands. The cursor simply filters the results with WHERE JOB_STATUS = 'MSGW', returning only the jobs that require attention.

Another implementation detail caught my attention. The JOB_NAME column returned by QSYS2.ACTIVE_JOB_INFO() already contains the fully qualified job name in number/user/name format — for example, 327961/BOB4IPGMR/PGMA — rather than just the short job name. IBM Bob generated a nested LOCATE and SUBSTR expression to extract the short job name for display in the subfile while preserving the fully qualified job name in SFQJOB. That hidden field was then used when constructing CL commands, ensuring the correct job was always referenced.

MSGWMON — QCMDEXC prototype
MSGWMON — QCMDEXC prototype with char OPTIONS(*VARSIZE), correctly generated by the ILE RPG Free Format Skill
MSGWMON — subfile load loop
MSGWMON — subfile load loop, fetching rows from the ACTIVE_JOB_INFO cursor
MSGWMON — ProcessOptions subroutine
MSGWMON — ProcessOptions subroutine reading changed subfile rows with READC and calling QCMDEXC

First Compilation

With both source members generated, I asked IBM Bob to compile them directly from the chat. Using IBM i Developer Mode, it ran CRTDSPF for the display file and CRTSQLRPGI for the SQLRPGLE program on the live IBM i system, then reported the compiler results in real time.

IBM Bob — compile output for MSGWDSPF and MSGWMON
CRTDSPF and CRTSQLRPGI output — both clean on the first attempt
Both source members compiled successfully on the first attempt. MSGWDSPF: CPC7301 — Display file created in BOB4IPGMR.
MSGWMON: Highest severity 00, zero errors, zero warnings. The 46 informational messages (RNF7066 and RNF7031) were expected because they relate to the message subfile formats managed through QMHSNDPM, rather than direct RPG I/O.

I then called the program. The display opened successfully, and the MSGW job that was active on the test system appeared in the subfile exactly as expected. At that point, I had gone from a single prompt to an implementation plan, generated source members, a successful compilation, and a working screen — all in less than fifteen minutes. However, compiling successfully was only the first step. The next stage was to verify that every operator action behaved correctly under real conditions.

My Enhancement Requests

After the first working version, I made two small enhancement requests:

  1. Remove the duplicate F5=Refresh label from the subfile control header, since it was already displayed in the FOOTER on line 23.
  2. Confirm that the job count was displayed in green when MSGW jobs were present and yellow when the list was empty.

IBM Bob updated only the requested changes. For the duplicate F5=Refresh label, it modified a single constant without regenerating the entire display file or changing unrelated code.

That level of precision stood out to me. Each enhancement was limited to the affected lines, making it easy to review the changes and understand exactly what had been modified. For small refinements and maintenance tasks, that targeted editing approach is far more useful than regenerating an entire source member.

The Runtime Bug

This is where things got more interesting.

After the enhancements compiled, I pressed F5 to refresh the screen, and the function key legend on lines 22–23 had disappeared. Every refresh wiped it. I reported it to IBM Bob the same way I would report a bug to a colleague:

"The function key footer disappears every time the subfile refreshes."

IBM Bob came back with a precise explanation:

"The root cause is that EXFMT MSGCTL performs a full-screen write. Without OVERLAY on the subfile control record, the 5250 data stream clears all screen positions not explicitly written by that operation, including the FOOTER record on lines 22–23. Adding OVERLAY to MSGCTL instructs the 5250 write to merge its output with the existing screen content rather than replacing it entirely."

MSGCTL before and after — OVERLAY keyword added
MSGCTL — OVERLAY added. Without it, EXFMT MSGCTL clears the separately-written FOOTER.
Before — MSGCTL (missing OVERLAY)
     A          R MSGCTL      SFLCTL(MSGSFL)
-                            SFLSIZ(9999)
-                            SFLPAG(0015)
After — MSGCTL (OVERLAY added)
     A          R MSGCTL      SFLCTL(MSGSFL)
+                            OVERLAY
+                            SFLSIZ(9999)
+                            SFLPAG(0015)

One DDS keyword. IBM Bob identified the problem, explained the underlying 5250 screen update behaviour, applied the fix, and after recompiling, the footer remained visible through every subsequent refresh.

The Bugs Bob Also Caught

The footer issue was the most visible problem, but it wasn't the only one. I want to be transparent about the other issues because they show how working with IBM Bob actually unfolded. The first version wasn't perfect, but the debugging experience was just as valuable as the initial code generation.

The Qualified Job Name Was Corrupt

Symptom Every operator action that executed a CL command — HLDJOB, ENDJOB, and the other options — failed with a "job not found" error.

The JOB_NAME column returned by QSYS2.ACTIVE_JOB_INFO() already contains the fully qualified job name in number/user/name format. The initial code rebuilt the value by concatenating JobNumber + '/' + JobUser + '/' + JobName. For a job such as 327961/BOB4IPGMR/PGMA, that produced 327961/BOB4IPGMR/327961/BOB4 — double-encoded and then truncated to 28 characters. As a result, every generated CL command referenced an invalid job name, producing errors such as "job not found" or "matching parenthesis not found", because the closing parenthesis was truncated along with the command string.

I reported the behaviour, and IBM Bob traced it back to the semantics of the ACTIVE_JOB_INFO() result set. It corrected the logic by using the fully qualified job name returned by the SQL service instead of rebuilding it. No other code needed to change.

SFQJOB assignment — before and after
SFQJOB corrected — direct assignment from JobRow.JobName, which is already the full qualified name
Before — double-encoded
- SFQJOB = %trimr(JobRow.JobNumber) + '/'
-        + %trimr(JobRow.JobUser)   + '/'
-        + %trimr(JobRow.JobName);  // already full!
- SFJOBNAM = %char(JobRow.JobName); // showed nbr/usr/name
After — direct assign
+ SFQJOB   = %char(JobRow.JobName);      // '327961/BOB4IPGMR/PGMA'
+ SFJOBNAM = %char(JobRow.JobShortName); // 'PGMA' (for display only)

The QCMDEXC Prototype Was Wrong

Symptom Every QCMDEXC call failed with "String contains a character that is not valid" — even for syntactically correct commands such as WRKJOB JOB(327961/BOB4IPGMR/PGMA).

The initial prototype declared the command parameter as varchar(32702) options(*varsize). When a VARCHAR variable is passed to a VARCHAR OPTIONS(*VARSIZE) parameter in ILE RPG, the compiler includes the internal two-byte length prefix as part of the data passed to the procedure. As a result, QCMDEXC received those two bytes at the beginning of the command string instead of the first command character. Although the command looked correct in the source code, the value received by QCMDEXC effectively began with two invisible characters before WRKJOB. The system therefore rejected the command with the "character not valid" error.

QCMDEXC prototype — varchar vs char
QCMDEXC prototype — varchar OPTIONS(*VARSIZE) (wrong) vs char OPTIONS(*VARSIZE) (correct)
Before — wrong
dcl-pr QCMDEXC extpgm('QCMDEXC');
-  Cmd    varchar(32702) options(*varsize) const;
   CmdLen packed(15:5)                   const;
end-pr;
After — correct
dcl-pr QCMDEXC extpgm('QCMDEXC');
+  Cmd    char(32702) options(*varsize) const;
   CmdLen packed(15:5)                 const;
end-pr;
Why this matters: This is the kind of problem that can take a long time to diagnose manually. The error message gives very little indication of the actual cause. A typical investigation would involve adding trace code, inspecting the command string, and eventually reviewing the ILE RPG calling convention closely enough to identify the parameter definition. IBM Bob identified the problem from the symptom description alone and generated the targeted fix without requiring broader changes to the program.

Option 5 Was Using the Wrong Command

Symptom Option 5 (Display Messages) failed with a "parameter not valid" error.

The initial implementation used WRKMSG JOB(...). The problem is that WRKMSG expects a message queue object — for example, WRKMSG MSGQ(QGPL/QSYSOPR). It does not support a JOB() parameter. To display the inquiry messages for a job, the correct command is WRKJOB JOB(...) OPTION(*MSG). I reported the issue, and IBM Bob identified the incorrect command and replaced it with the appropriate one. It was a small change, but an important one. If an operator selected option 5 and immediately received a command failure, it would reduce confidence in the application.

Option 5 corrected — WRKJOB OPTION(*MSG)
Option 5 corrected — WRKJOB JOB(...) OPTION(*MSG) instead of the invalid WRKMSG JOB(...)

Compilation Summary and Final Working Screen

Compilation Summary

Final compile — highest severity 00
Final CRTSQLRPGI output — highest severity 00
After the fixes, both source members compiled cleanly. Highest severity: 00 · Errors: 0 · Warnings: 0. The 46 informational messages (RNF7066 and RNF7031) were expected. They relate to the message subfile formats managed through QMHSNDPM, which is the standard IBM i approach for providing interactive program feedback. They do not indicate a problem with the application.

Live Screen — IBM i 5250 Terminal

MSGWMON running on IBM i — MSGW job monitor screen
MSGWMON live on IBM i — MSGW jobs in the subfile, green job count, persistent function key footer

An L1 analyst opens the screen and immediately sees only the jobs that require attention. They can type 5 to view the waiting message, 2 to work with the job, or 3 to hold it. There are no IBM i commands to remember or navigate. The job counter is displayed in green when MSGW jobs require attention and yellow when the queue is clear.

Productivity Comparison

The table below compares the time I would typically expect to spend developing this application manually with the time it took using IBM i Developer Mode in IBM Bob Premium Package for i (PPi).

TaskManuallyWith IBM i Developer Mode
DDS subfile design and layout2–3 hours~5 minutes
RPGLE subfile load and display logic3–4 hours~10 minutes
SQL cursor with ACTIVE_JOB_INFO45–60 minutesIncluded
Message subfile wiring (QMHSNDPM)1–2 hoursIncluded
Debugging the OVERLAY footer issue30–60 minutes~2 minutes
Diagnosing the varchar/char QCMDEXC defect1–2 hours~5 minutes
Total~2 business days< 1 hour

One issue deserves a special mention. The varchar/char QCMDEXC prototype problem provides very little information about where to start looking. An experienced IBM i developer could easily spend an hour tracing the command string and reviewing the ILE RPG calling conventions before identifying the parameter definition. I reported the symptom, and IBM Bob identified the underlying cause and generated the required fix.

What Made This Possible

Everything demonstrated in this article — from IBM i Developer Mode and the IBM i skills to live compilation, SQL service access, and runtime diagnostics — was made possible by the IBM Bob Premium Package for i (PPi). What stood out to me was how these capabilities worked together. Instead of generating code in isolation, IBM Bob could compile it on a live IBM i system, interpret compiler output, diagnose runtime issues, apply targeted fixes, and help me iterate quickly. That changed the development experience from repeatedly switching between tools to working through the entire implementation in a single conversation.

The Final Application — IBM i Screens

Watch It in Action

A full walkthrough of the MSGW Job Monitor running live on IBM i, built using IBM i Developer Mode in IBM Bob Premium Package for i (PPi).

Next Steps

To find out more, check out these resources: