Previously Ghost has been part of the autodiff package Yota and was used to break down complex functions into the list of primitives amenable to differentiation. Other use cases include function serialization, analysis or modification, as well as providing a general graph representation.
As an experimental feature, Ghost also supports loop operation, making it suitable for many dynamic graph problems.
Ghost has some intersecting functionality with IR-level packages such as Cassette, IRTools, CodeInfoTools, etc., but works on a higher level (i.e. no segfaults due to incorrectly inserted operation) and makes emphasis on linearized graph representation.
SymbolicTracing looks interesting and the two packages certainly have similar approaches to tracing. A few differences I see though (based on the README):
SymbolicTracing works only with abstract type while Ghost can as well trace through concrete types and struct fields
SymbolicTracing doesn’t seem to handle control flow; Ghost can follow branches, including conditions and loops
Loops in Ghost can also be traced as a separate operation
I’m not sure it’s possible to include operations out of the dependency graph in SymbolicTracing (e.g. println() statement); in Ghost you can have both - a pure computational graph and a graph with side effects
In general, Symbolic* packages seem to be more oriented to pure symbolic graphs, while Ghost’s Tape is an abstraction for any kind of computation