The programming really is nothing too drastic
For the average LZ setup
First part will usually be an indicator and length of file (might even have a length of decompressed file in some cases but this is not certain), so much so normal for many file types. If there is a header detailing location of sections if they are what is actually compressed (better to decompress small sections rather than have to unpack a whole file to get 200 bytes -- if you have ever had a 7zip file take ages to decompress a single file from a big collection of them then this is that in the real world) it will probably be here too.
LZ itself then usually amounts to
[Whatever header stuff you are doing] and get to start of compressed section
Check flag (assuming there is one, some really simplistic ones might just expect you to start and count upwards)
if not compressed copy data to final setup, go to next section (usually a fixed number of bytes away, though can be included in the flag). This is also the cheap way of faking it -- if every flag is "not compressed, go to next" then you don't have to worry about actually recompressing and the game will not care either (Hopefully you can persuade your cartridge storage division of the company you are making this for to give you the extra space).
if compressed then read compression value. It will have a value for number of bits to read (might be slightly more complex as you will have a minimum to make it worth it*) and number of bytes from where you are to go back to find it.
Repeat until end of file/compressed data section (which is what the header might have told you).
*there is no point in saying go here and read 0 bytes, or less bytes than it took to have the compressed flag. To that end a read value of 0 might well mean 3 bytes and start counting up from there so you also have a higher maximum just in case that is useful.
Custom LZ family compressions on consoles or indeed PC tend mostly to vary the flags and split between number of bits kicked to read length and number of bits kicked to location, which will very quickly break any compression hardcoded to expect a particular split but be similarly trivially sorted when it comes down to it. Can also start from the end of the file (see BLZ) or the header/file locations bit might be stored there, and some particularly silly types might read forwards and backwards or count from an absolute position in the file (go to byte ?? and copy $$ from it sort of thing) but absolute is rare and usually makes less sense/makes for worse compression so yeah.
RLE (run length encoding, more common on older consoles without as much computing power) is just a simplistic version of this; skip along though the file, if meeting compressed flag then repeat this next bit for however many bytes it tells you to, get to end of file)
Dictionary compressions (like Huffman, which is rare as a general thing) are simple substitutions most of the time. Can be more long winded to do as elegant code but in the end you get to go through everything and where it has one value on the list of substitutions you take the (hopefully smaller) value it is stored as and replace it with whatever the dictionary/lookup table says to replace it with.
Recompression means you can either adopt the existing table or maybe define a new one -- scan through the file noting particular repeating patterns, make new table based on these and it might actually make it smaller.
If you want some example source code then https://www.romhacking.net/utilities/826/
is good stuff, or maybe https://github.com/barubary/dsdecmp
. Both are for the GBA/DS but as above it is all fairly similar in the end.
Also if you have not checked extensions, header magic stamps or the like out in a search then might want to do that too.