How I Used a Graph Database to Rebuild Lost Source Code with AI
Banks, space programs, and old industrial systems still run on compiled programs (.exe files, Linux ELF files, firmware) whose source code was lost years ago. The authors retired, and the tools used to build them no longer exist. The standard way to look inside is a decompiler like NSA's Ghidra, wh

Banks, space programs, and old industrial systems still run on compiled programs (.exe files, Linux ELF files, firmware) whose source code was lost years ago. The authors retired, and the tools used to build them no longer exist.
The standard way to look inside is a decompiler like NSA's Ghidra, which turns machine code back into C-like text. But the output is rough. It won't compile, and values show up only as raw memory addresses with no explanation.
Here is a function from our billing test:
double compute_progressive_tax ( double amount ) { double * brackets = ( double * ) 0x00405000; // what is this?... } Enter fullscreen mode Exit fullscreen mode The function reads a table at address 0x00405000, but nothing in its code says what's in the table. Another function, two calls away, filled that table with the tax brackets when the program started.
An AI model that sees only this one function can't know that. So it guesses, usually a flat 10% rate. We call this the context cliff: the answer exists in the program, but outside what the model can see. On our billing test, a standalone model matched the original program's results only 35% of the time.
A graph database stores things (nodes) and the links between them (edges). A compiled program is already shaped like that: functions call other functions, and functions read and write memory.
GhostGraph loads the decompiled program into FalkorDB as a graph:
Now the missing information is one query away. Cypher, FalkorDB's query language, follows the link from the function that reads an address to the function that wrote it:
MATCH ( target: Function { name: $function_name }) - [:READS ] -> ( mem: GlobalMemory ) <- [:WRITES ] - ( initializer: Function ) RETURN mem.address, initializer.name, initializer.pseudocode Enter fullscreen mode Exit fullscreen mode In plain words: "Find the memory this function reads, then find whoever wrote to it." For the billing example, this returns the initializer function with the real brackets: 0% up to 100, 5% up to 500, and 12% up to 2000.
Four AI agents share the graph as their common memory:
We also used FalkorDB's built-in PageRank (a score of which functions are most connected) to decide which functions to rebuild first, and shortest path queries to trace call chains. Separate graphs hold each target, so billing, Space Invaders, and Lunar Lander never mix.
When rebuilt code fails a test, the agent writes the failure into the graph:
CREATE ( c ) - [:FAILED_ON { diff: $diff }] -> ( t ) Enter fullscreen mode Exit fullscreen mode On the next attempt, the agent reads those failures first and fixes the exact edge case instead of repeating the same mistake. The graph is both the knowledge base and the agents' memory of what went wrong.
The Lunar Lander shows why the graph matters. Without it, the model assumed Earth's gravity (9.81 m/s²). With it, the agents found the real lunar value (1.62 m/s²) in a memory table, and the rebuilt physics landed the module.
Each verified result also gets a signed certificate (HMAC-SHA256) that records the tests passed. Changing anything afterward breaks the signature, so anyone can check that a result is real.
Graph queries gave the model the one thing it was missing: connections between functions that its context window never held. And storing failures in the graph made the agents improve with each attempt.
Built for the WeMakeDevs × FalkorDB Graph Hacks hackathon. Thanks to both teams.