Files
agenticCode/x-docs/presentation.md
Ingo Schnabel 2c56eea161 Remove MCP
2026-08-04 12:57:08 +02:00

6.4 KiB

AgenticCode — What It Does

The Problem

Big Natural (and Java) codebases are hard to understand. A single feature may spread across dozens of small programs linked by CALLNAT calls and shared data areas. Figuring out what a feature does — or what it would take to rewrite it — means reading many files by hand.

AI assistants (like Claude) cannot help much here today. They can read source files one by one, but they have no way to answer basic questions like:

  • Who calls this program?
  • Which database tables does this feature read or write?
  • Where does the value in this field come from?

What AgenticCode Does

AgenticCode reads a Natural/Java codebase, builds a graph of everything it finds, and gives AI agents a simple API to query that graph.

Source files  →  Parse  →  Graph (Neo4j)  →  Enrich  →  Agent API

An agent calls the API like a tool — asking questions in plain HTTP — and gets structured answers back, without reading any source files itself.


What Gets Extracted

The parser reads each Natural program and pulls out:

  • Subroutines — every DEFINE SUBROUTINE block with its line range
  • Calls — every CALLNAT and PERFORM, including dynamic ones (CALLNAT #VAR)
  • Database access — every READ, FIND, STORE, UPDATE, DELETE with the table name and full SQL text
  • Data declarations — every field in DEFINE DATA, with type, length, and scope (PARAMETER/LOCAL/GLOBAL)
  • Includes — every PARAMETER USING and LOCAL USING reference links the program to its LDA or PDA file; .lda and .pda files are fully parsed (fields, levels, REDEFINE blocks, VIEW OF table links)
  • Field references through includes — MOVE STRUCT.FIELD TO ... or bare MOVE SORT-KEY TO ... are resolved to the actual field declared in the included data area
  • Variable reads and writes — MOVE, COMPUTE, ASSIGN, arithmetic (ADD/SUBTRACT/etc.)
  • Control flow — IF, FOR, REPEAT, DECIDE
  • Dispatch tables — DECIDE ON VALUE blocks that map a field value to a called program

For Java it extracts classes, methods, fields, cross-class calls, and JPA entity mappings (@Entity, @Column, inherited columns).


What an Agent Can Ask

Call graph

  • Who calls this program? (/modules/{name}/callers) — who depends on it
  • What does this program call? (/modules/{name}/callees) — its direct dependencies, filtered by ?scope=external (CALLNAT) or ?scope=internal (PERFORM)
  • What is the full call tree? (/modules/{name}/call-tree?depth=N) — everything reachable, up to N hops deep

Database access

  • Which tables does this feature touch? (/modules/{name}/db-accesses?depth=N) — including tables accessed by called subprograms
  • What is the exact SQL? (/modules/{name}/sql-statements?depth=N) — full statement text, table, view, line range
  • What columns does this table have? (/db-tables/{name}/columns) — from Natural data areas or Java @Entity annotations

Data areas and includes

  • Which data areas does this program include? (/modules/{name}/data-structures) — lists every PARAMETER/LOCAL USING area and inline group, with type (PDA/LDA/GDA), field count, and file
  • What fields are in this data area? (/data-structures/{name}/fields) — flattened list with Natural types (A8, I4), constant values, nesting level, and scope

Dataflow

  • Where does this field's value go? (/variables/{name}/flow-forward) — follows it forward across CALLNAT argument lists
  • Where does this field's value come from? (/variables/{name}/flow-backward) — traces it back to its origin
  • Which programs write and which programs read this shared PDA field? (/variables/{name}/field-flow) — across the whole call graph
  • Find by name (/search/identifier?name={n}) — any identifier across all programs
  • Find by value (/search/value?value={v}) — find which program assigns a string like 'WGEAGB0S' to a field

How Ingest Works

Ingest is split into two steps so large codebases stay fast:

  1. Fast pass (/ingest-call-graph) — reads all files, builds the call graph. 6,309 Natural files in 67 seconds. Skips the expensive field-level resolution.
  2. Deep pass (/ingest/{name}) — fully resolves a single program and all programs it depends on. A 56-program tree in 5 seconds, even when the full call graph is already loaded.

Endpoints that need field-level data return a clear 409 error with a nextAction hint if a program has only been fast-ingested — so an agent knows exactly what to ask an operator to do next.


Numbers from a Real Codebase (upms)

What Result
Files ingested (fast pass) 6,309 in 67 s
Deep ingest of a 56-program tree 5.2 s
Dynamic CALLNAT targets resolved for one dispatcher 124 programs
Dispatch table rows recovered for KDWWIFN0 ~140, matching a hand-built CSV

What This Enables

A question like "what would it take to rewrite WGEAGB0S in Spring Boot?" that used to take hours of manual reading now takes one agent session:

  1. Overview: callers, callees, subroutines
  2. Full call tree — the scope of the feature
  3. All database tables touched, including behind CALLNAT hops
  4. Exact SQL to port to Panache/JPA
  5. Column schema for the new @Entity class
  6. Where the key field comes from (dataflow)
  7. Who else depends on this program (blast radius)

The agent can then generate a typed Spring Boot service — with the right entity mapping, business logic, and a complete picture of what else is affected.


Tech Stack

Component Technology
Server Quarkus (Java 21, Virtual Threads)
Graph DB Neo4j 5.x
Natural parser Custom (no open-source parser exists)
Java parser JavaParser library
API JAX-RS / RESTEasy Reactive
Tests JUnit 5 + RestAssured + Testcontainers