Go, 372 bytes
import(."strings";."strconv")
func d(s string)(k string){for _,l:=range Split(s,"\n"){i,_:=ParseInt(NewReplacer(" ","0","O","1","X","2").Replace(l),3,64)
k+=string('A'+i)}
return ReplaceAll(k,"["," ")}
func e(s string)(k string){q:=ReplaceAll(s," ","[")
for _,r:=range q{k+=NewReplacer("0"," ","1","O","2","X").Replace(FormatInt(int64(r-'A'),3))+"\n"}
return Trim(k,"\n")}
Attempt This Online!
Explanation
Decoder
import(."strings";."strconv")
func d(s string)(k string){
for _,l:=range Split(s,"\n"){ // for each line...
i,_:=ParseInt( // turn the string into an int
NewReplacer(" ","0","O","1","X","2") // define the replacements
.Replace(l), // replace the chars
3,64) // turn it into trinary
k+=string('A'+i)} // append to the output string
return ReplaceAll(k,"["," ")} // replace `[` with spaces
Encoder
import(."strings";."strconv")
func e(s string)(k string){
q:=ReplaceAll(s," ","[") // replace `[` with spaces
for _,r:=range q{ // for each character...
k+=NewReplacer("0"," ","1","O","2","X") // define the replacements...
.Replace( // and apply onto...
FormatInt(int64(r-'A'),3)) // the character, turned into trinary
+"\n"} // and add a newline
return Trim(k,"\n")} // trim the final newline