How to make ''sudo launchctl limit' change permanent?

You can create a launch daemon to run that command on every startup. Create /Library/LaunchDaemons/private.maxfiles.plist with the following contents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>private.maxfiles</string>
        <key>ProgramArguments</key>
        <array>
            <string>launchctl</string>
            <string>limit</string>
            <string>maxfiles</string>
            <string>10240</string>
            <string>10240</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>

Launchd has two keys — HardResourceLimits and SoftResourceLimits — that can be used to place limits on the resources of jobs. They take a dictionary of integers, so you can add something like the following to your launchd plist to get a permanent solution:

<key>HardResourceLimits</key>
<dict>
    <key>NumberOfFiles</key>
    <integer>500</integer>
</dict>

This should cap out the number of files that process has open at 500.

I'm not really certain what the difference between 'soft' and 'hard' limits are, though the man page for launchd.plist says (cryptically):

NumberOfFiles

The maximum number of open files for this process. Setting this value in a system wide daemon will set the sysctl(3) kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits) value in addition to the setrlimit(2) values.

sysctl(3) has no man page on my machine, and it's too early in the morning for me to go do a google search. I'll suggest, though, that what you're really looking at is a coding error, and you should fix this in the daemon, not rely on launchd. launchd likes to have flexible control over things, and would rather that users avoid dictating too much.