./run will produce its output to stdout if not given a file argument (which is customary in Unix/Linux), then you can simply use:
./run | xz -c >output.txt.xz
If it needs a filename argument, but if it's fine writing to a pipe, then you can either use a special device such as
/dev/fd/1 (both should be equivalent), like so:
./run /dev/stdout | xz -c >output.txt.xz
Or you can use process substitution, which is typically available in most modern shells such as bash, zsh, or ksh, which will end up using a device from
/dev/fd behind the scenes to accomplish the same:
./run >(xz -c >output.txt.xz)
This last one also needs
./run to be able to write to a pipe, but it should work better than the others if
./run writes to
output.txt and to stdout in its normal operation, in which case the output would get mixed up if you redirect both to stdout.
Programs are usually ok writing to a pipe, but some of them might want to seek and rewind to offsets within an output file, which is not possible in a pipe. If that's the case, then writing to a temporary file and then compressing it is probably all you can do.