There are a lot of ways to write a serial protocol depending on what functionality you might want and how much error checking you need.
Some of the common things you see in point to point protocols are:
End of message
The simplest ASCII protocols just have an end of message character sequence, often
\n as this is what gets printed when the enter key is hit. Binary protocols might use
0x03 or some other common byte.
Start of message
The problem with just having end of message is that you don't know what other bytes have already been received when you send your message. These bytes would then be prefixed to the message and cause it to be interpreted wrongly. For example, if the Arduino just woke from sleep there might be some garbage in the serial buffer. To get around this you have a start of message sequence. In your example,
^, in binary protocols often
If the message can be corrupted we need some error checking. This could be a checksum or a CRC error or something else.
It could be that the checksum adds to a control character, such as the 'start of message' or 'end of message' byte, or the message contains a value equal to a control character. The solution is to introduce an escape character. The escape character is placed before a modified control character so that the actual control character is not present. E.g. if a start character is 0x02, using the escape character 0x10 we can send the value 0x02 in the message as the byte pair 0x10 0x12 (byte XOR control character)
If a message is corrupted we could request a resend with a nack or retry message, but if multiple messages have been sent then only the latest message can be resent. Instead the packet can be given a number that rolls over after a certain number of messages. For example, if this number is 16, the transmitting device can store the last 16 messages send and if any were corrupted the receiving device can request a resend using the packet number.
Often in binary protocols you see a length byte which tells the receiving device how many characters are in the message. This adds another level of error checking as if the correct number of bytes were not received then there was an error.
When coming up with a protocol for Arduino the first consideration is how reliable is the communications channel. If you are sending over most wireless mediums, XBee, WiFi, etc, there is already built in error checking and retries and thus no point in putting these in your protocol. If you are sending over RS422 for a couple of kilometres then it will be necessary. The things I would include are the start of message and end of message characters, as you have. My typical implementation looks something like:
Delimiting the data parts with a comma allows for easy parsing, and the message is sent using ASCII. ASCII protocols are great because you can type messages into the serial monitor.
If you want a binary protocol, maybe to shorten the message sizes, you will have to implement escaping if a data byte can be the same as a control byte. Binary control characters are better for systems where the full spectrum of error checking and retries is desired. The payload can still be ASCII if desired.