Implementing Todo in Haskell
It looks good overall.

I see two possible problems.

Race condition in deleteTodo

Running the program twice at the same time you might lose one change because reading the old file, writing the new file and renaming is not atomic.

You can avoid that problem when using a "tododir" with one single file per item. It will also scale better with the number of todo items. Note, that that's very similar to why maildir is superior to mbox. See the rationale at djb's site.

Error handling is missing

You don't catch exceptions when doing file operations and use the partial read. For that simple interactive program I would not catch file operation errors but would surely use readMaybe.