pb-modify

star 1

Use when modifying PowerBuilder source code (.srw, .srd, .sru, .srm files). Guides the complete workflow from reading to compilation. MUST be used for any PB code change.

juliendetilleux By juliendetilleux schedule Updated 3/13/2026

name: pb-modify description: Use when modifying PowerBuilder source code (.srw, .srd, .sru, .srm files). Guides the complete workflow from reading to compilation. MUST be used for any PB code change. tools: Glob, Grep, Read, Write, Edit, Bash, TodoWrite

PowerBuilder Code Modification Workflow

CRITICAL RULES — Anti-Hallucination

These rules exist because Claude has caused real compilation failures by hallucinating variable names, control names, and function signatures. Every rule below comes from a real incident.

  1. NEVER invent a variable, control, or function name. If you haven't seen it in the source code via pb_read_object, it does not exist. The incident with dw_purline_quickfeed (correct name: dw_purlinelimite_quickfeed) cost 3 hours of debugging.

  2. NEVER use Edit or Write on .sr files.* These tools corrupt PB encoding (BOM, CRLF, tabs). A PreToolUse hook will block you. Always use pb_modify_script.

  3. NEVER declare a variable without checking existing declarations. The ld_qtyold duplicate declaration incident caused a compilation failure that was invisible in Deploy mode.

  4. NEVER skip the verification step (Step 5). You MUST re-read the modified file to confirm your change is correct before compiling.

  5. NEVER modify forward, on create, or on destroy sections. These are generated by the PB IDE and will break the object if altered.

  6. NEVER guess a DataWindow column name. Use pb_dw_get_columns or read the .srd file to get the actual column names.

  7. NEVER copy code between windows without checking control names. Each window has its own controls with specific names. What works in w_quickpurchase may reference controls that don't exist in w_quickpurchaselimite.


MANDATORY: Follow ALL steps for EVERY PB code modification

Step 1: Understand — Read Everything First

Before changing any PowerBuilder file, you MUST gather complete context:

  1. Read the target object using pb_read_object to get the FULL source + parsed metadata
  2. Check the inheritance chain using pb_get_inheritance — what does this inherit from? What inherits from it?
  3. Check dependencies using pb_get_dependencies — who references this object? What could break?
  4. Get a summary using pb_get_object_summary for a quick structural overview

NEVER modify a PB file without completing all 4 reads above.

Step 2: Inventory — Collect All Names

Before writing any code, build an explicit inventory of names that exist in the target scope. This prevents hallucination of non-existent identifiers.

2a. Variables inventory

From the pb_read_object output, list ALL variables declared in the function/event you're modifying:

  • Instance variables (in type variables ... end variables)
  • Local variables (declared with type varname at the top of the function/event)
  • Function parameters

CHECK: Is the variable you want to use already declared? If yes, DO NOT re-declare it. CHECK: Does the variable name you're about to use match an existing one EXACTLY? (case-insensitive in PB, but names must match)

2b. Controls inventory

If your code references any UI control (DataWindow, button, text field, etc.), verify it exists:

  • Look in the pb_read_object output for the control's type declaration
  • For DataWindow controls, confirm the exact name (e.g., dw_purline vs dw_purlinelimite — these are DIFFERENT controls)
  • If unsure, use pb_search_code to find the control name in the source

2c. DataWindow columns inventory

If your code accesses DataWindow columns (via GetItemString, SetItem, GetItemNumber, etc.):

  • Use pb_dw_get_columns or pb_get_datawindow_sql to get the actual column list
  • Or read the .srd file directly
  • NEVER guess a column name — PB gives no error at compile time for wrong column names, it crashes at RUNTIME

2d. Functions inventory

If calling a function on an object:

  • Verify the function exists in the object or its ancestor chain via pb_read_object or pb_search_code
  • Check the function signature (parameter types and count)

Step 3: Plan the Modification

Before writing code, state explicitly:

  • What you're changing (which event/function/variable)
  • Where exactly in the file (after which line/block)
  • Names used: list every variable, control, and function your new code references, and confirm each one was found in Step 2
  • Ancestor impact: does this change affect behavior inherited by descendants?

If you cannot confirm a name from Step 2, STOP and ask the user or search for it.

Step 4: Apply the Modification

Use pb_modify_script for targeted find-and-replace:

  • The tool creates automatic .bak backups
  • The tool verifies unique occurrence before replacing
  • The tool normalizes CRLF line endings
  • The tool auto-syncs to the .pbl/ subfolder for compilation

For new functions/events, insert at the correct location in the file:

  • Instance variables go in type variables ... end variables section
  • Function prototypes go in forward prototypes ... end prototypes
  • Functions go after the end type declaration
  • Events go after functions

IMPORTANT: When modifying similar code in multiple files (e.g., w_quickpurchase AND w_quickpurchaselimite):

  • Do NOT copy-paste blindly between files
  • Re-read each target file with pb_read_object first
  • Re-do the names inventory (Step 2) for EACH file — controls differ between windows

Step 5: Verify — Re-read the Modified File

This step is MANDATORY. Do NOT skip it.

After each pb_modify_script call:

  1. Re-read the modified file using pb_read_object (or the specific section with pb_read_object + section parameter)
  2. Verify the change is correct: the replacement landed in the right place, no surrounding code was damaged
  3. Check for duplicates: search for the variable/function name in the full file to ensure you haven't created a duplicate declaration
  4. Verify the .pbl/ sync: pb_modify_script reports pbl_synced in its output — confirm it's not null

Only proceed to Step 6 if the re-read confirms the modification is correct.

Step 6: Compile and Validate

  1. Run pb_validate_syntax for quick structural check
  2. Run pb_compile for full compilation (uses Full Build by default — gives detailed errors like C0081, C0015)
  3. Read the errors carefully:
    • C0081: Duplicate variable → you declared a variable that already existed (Step 2 failure)
    • C0015: Undefined variable → you used a name that doesn't exist (hallucination)
    • C0114: Error scanning object source entry → encoding corruption (should not happen with pb_modify_script)
    • C0248: Missing definition of top-level type$PBExportHeader$ or forward section damaged
  4. If compilation succeeds, PBDs auto-copy to the exe directory if copy_pbds: true

Step 7: Error Recovery

If compilation fails:

  1. Read the error messages — they tell you EXACTLY what's wrong
  2. The .bak backup file exists — restore with pb_modify_script if needed
  3. Go back to Step 2, re-inventory, fix the issue
  4. Re-compile
  5. NEVER leave the codebase in a broken compilation state

PowerScript Conventions

Variable naming

  • is_ = instance string, il_ = instance long, ib_ = instance boolean
  • id_ = instance decimal/date, ii_ = instance integer
  • ls_ = local string, ll_ = local long, lb_ = local boolean, ld_ = local decimal
  • as_ = argument string, al_ = argument long, etc.

Function naming

  • of_ = object function (public method)
  • wf_ = window function (private to window)
  • gf_ = global function

Event naming

  • ue_ prefix = user-defined events (custom)
  • Standard events: open, close, clicked, constructor, destructor

Object naming

  • w_ = window, nvo_ = non-visual object, uo_ = user object (visual)
  • d_ = datawindow, m_ = menu
  • st_ = static text, sle_ = single line edit, mle_ = multi-line edit
  • cb_ = command button, dw_ = datawindow control
  • ddlb_ = dropdown list box, rb_ = radio button, cbx_ = checkbox

File structure (.sr* files)

$PBExportHeader$objectname.srw
forward                          ← DO NOT MODIFY
global type ... from ...
end type
end forward

shared variables                 ← shared across instances
end variables

type variables                   ← instance variables
end variables

forward prototypes               ← function declarations
end prototypes

type prototypes                  ← more declarations
end prototypes

event open;...end event          ← events
public function ...end function  ← functions

on objectname.create             ← lifecycle — DO NOT MODIFY
on objectname.destroy            ← lifecycle — DO NOT MODIFY

Common patterns

  • SQLCA = default transaction object (database connection)
  • After ANY SQL statement, ALWAYS check SQLCA.SQLCode (1 = success, -1 = error)
  • this. = current object, parent. = parent window
  • destroy = free memory for dynamic objects (MUST be called or memory leaks)
  • trigger event = fire event now, post event = queue for later

Checklist Summary

Before submitting your modification, verify:

[ ] Step 1: Read object, inheritance, dependencies, summary — ALL DONE
[ ] Step 2: All variable names confirmed from source (not invented)
[ ] Step 2: All control names confirmed from source (not invented)
[ ] Step 2: All DW column names confirmed (not guessed)
[ ] Step 2: All function names/signatures confirmed
[ ] Step 3: Plan stated with explicit name list
[ ] Step 4: Used pb_modify_script (NOT Edit/Write)
[ ] Step 5: Re-read modified file — change is correct
[ ] Step 5: No duplicate declarations introduced
[ ] Step 5: pbl_synced confirmed
[ ] Step 6: pb_compile succeeded (Full Build)
[ ] Step 7: No errors left — codebase compiles clean
Install via CLI
npx skills add https://github.com/juliendetilleux/powerbuilder-toolkit --skill pb-modify
Repository Details
star Stars 1
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
juliendetilleux
juliendetilleux Explore all skills →