Cotlib
cotlib is a secure, high-performance Go library for parsing, validating, and generating Cursor-on-Target (CoT) XML messages. It features a comprehensive, embedded type catalog with metadata and XSD catalogue, robust validation logic, and LLM/AI-friendly search APIs. Designed for reliability, composability, and security.
Install / Use
/learn @NERVsystems/CotlibQuality Score
Category
Development & EngineeringSupported Platforms
README

'…we want the target dead or saved…we gotta get away from platform centric thinking…and we gotta focus on this thing where the sum of the wisdom is a cursor over the target…and we're indifferent [to the source]' — Gen. John Jumper
CoT Library
A comprehensive Go library for creating, validating, and working with Cursor-on-Target (CoT) events.
Features
- High-performance processing: Sub-microsecond event creation, millions of validations/sec
- Complete CoT event creation and manipulation
- XML serialization and deserialization with security protections
- Full CoT type catalog with metadata
- Zero-allocation type lookups and optimized memory usage
- How and relation value support with comprehensive validation
- Coordinate and spatial data handling
- Event relationship management
- Type validation and registration
- Secure logging with slog
- Thread-safe operations
- Detail extensions with round-trip preservation
- GeoChat message and receipt support
- Predicate-based event classification
- Security-first design
- Wildcard pattern support for types
- Type search by description or full name
Installation
go get github.com/NERVsystems/cotlib
Note: Schema validation relies on the libxml2 library and requires CGO to be enabled when building.
See MIGRATION.md for guidance when upgrading from older versions.
Usage
Creating and Managing CoT Events
package main
import (
"fmt"
"log/slog"
"os"
"github.com/NERVsystems/cotlib"
)
func main() {
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
// Create a new CoT event
event, err := cotlib.NewEvent("UNIT-123", "a-f-G", 37.422, -122.084, 0.0)
if err != nil {
logger.Error("Failed to create event", "error", err)
return
}
// Add detail information
event.Detail = &cotlib.Detail{
Contact: &cotlib.Contact{
Callsign: "ALPHA-7",
},
Group: &cotlib.Group{
Name: "Team Blue",
Role: "Infantry",
},
}
// Add relationship link
event.AddLink(&cotlib.Link{
Uid: "HQ-1",
Type: "a-f-G-U-C",
Relation: "p-p",
})
// Convert to XML
xmlData, err := event.ToXML()
if err != nil {
logger.Error("Failed to convert to XML", "error", err)
return
}
fmt.Println(string(xmlData))
}
Building Events with EventBuilder
builder := cotlib.NewEventBuilder("B1", "a-f-G", 34.0, -117.0, 0).
WithContact(&cotlib.Contact{Callsign: "ALPHA"}).
WithGroup(&cotlib.Group{Name: "Team Blue", Role: "Infantry"}).
WithStaleTime(time.Now().Add(10 * time.Second))
event, err := builder.Build()
if err != nil {
log.Fatal(err)
}
_ = event
Parsing CoT XML
package main
import (
"errors"
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
xmlData := `<?xml version="1.0" encoding="UTF-8"?>
<event version="2.0" uid="UNIT-123" type="a-f-G" time="2023-05-15T18:30:22Z"
start="2023-05-15T18:30:22Z" stale="2023-05-15T18:30:32Z">
<point lat="37.422000" lon="-122.084000" hae="0.0" ce="9999999.0" le="9999999.0"/>
<detail>
<contact callsign="ALPHA-7"/>
<group name="Team Blue" role="Infantry"/>
</detail>
</event>`
// Parse XML into CoT event
event, err := cotlib.UnmarshalXMLEvent(context.Background(), []byte(xmlData))
if err != nil {
fmt.Printf("Error parsing XML: %v\n", err)
return
}
// Access event data
fmt.Printf("Event Type: %s\n", event.Type)
fmt.Printf("Location: %.6f, %.6f\n", event.Point.Lat, event.Point.Lon)
fmt.Printf("Callsign: %s\n", event.Detail.Contact.Callsign)
// Check event predicates
if event.Is("friend") {
fmt.Println("This is a friendly unit")
}
if event.Is("ground") {
fmt.Println("This is a ground-based entity")
}
}
Handling Detail Extensions
CoT events often include TAK-specific extensions inside the <detail> element.
cotlib preserves many of these extensions and validates them using embedded TAKCoT schemas. These extensions go beyond canonical CoT and include elements such as:
__chat__chatReceipt__chatreceipt__geofence__serverdestination__video__grouparchiveattachmentListenvironmentfileshareprecisionlocationtakvtrackmissionstatusshapestrokecolorstrokeweightfillcolorlabelsonuidbullseyerouteInfocolorhierarchylinkusericonemergencyheightheight_unitremarks
The remarks extension now follows the MITRE CoT Remarks Schema and includes
a <remarks> root element, enabling validation through the
tak-details-remarks schema.
All of these known TAK extensions are validated against embedded schemas when decoding and during event validation. Invalid XML will result in an error. Chat messages produced by TAK clients often include a <chatgrp> element inside <__chat>. cotlib first validates against the standard chat schema and automatically falls back to the TAK-specific tak-details-__chat schema so these messages are accepted.
Example: adding a shape extension with a strokeColor attribute:
event.Detail = &cotlib.Detail{
Shape: &cotlib.Shape{Raw: []byte(`<shape strokeColor="#00FF00"/>`)},
}
Any unknown elements are stored in Detail.Unknown and serialized back
verbatim.
Unknown extensions are not validated. Although cotlib enforces XML size and depth limits, the data may still contain unexpected or malicious content. Treat these elements as untrusted and validate them separately if needed.
xmlData := `<?xml version="1.0"?>
<event version="2.0" uid="EXT-1" type="t-x-c" time="2023-05-15T18:30:22Z" start="2023-05-15T18:30:22Z" stale="2023-05-15T18:30:32Z">
<point lat="0" lon="0" ce="9999999.0" le="9999999.0"/>
<detail>
<__chat chatroom="room" groupOwner="false" senderCallsign="Alpha">
<chatgrp id="room" uid0="u0"/>
</__chat>
<__video url="http://example/video"/>
</detail>
</event>`
evt, _ := cotlib.UnmarshalXMLEvent(context.Background(), []byte(xmlData))
out, _ := evt.ToXML()
fmt.Println(string(out)) // prints the same XML
The id attribute on __chat and __chatreceipt elements is optional.
Chat now exposes additional fields such as Chatroom, GroupOwner,
SenderCallsign, Parent, MessageID and a slice of ChatGrp entries
representing group membership.
GeoChat Messaging
cotlib provides full support for GeoChat messages and receipts. The Chat
structure models the __chat extension including optional <chatgrp> elements
and any embedded hierarchy. Incoming chat events automatically populate
Event.Message from the <remarks> element. The Marti type holds destination
callsigns and Remarks exposes the message text along with the source, to,
and time attributes.
Chat receipts are represented by the ChatReceipt structure which handles both
__chatReceipt and TAK-specific __chatreceipt forms. Parsing falls back to the
TAK schemas when required so messages from ATAK and WinTAK are accepted without
extra handling.
Example of constructing and serializing a chat message:
evt, _ := cotlib.NewEvent("GeoChat.UID.Room.example", "b-t-f", 0, 0, 0)
evt.Detail = &cotlib.Detail{
Chat: &cotlib.Chat{
ID: "Room",
Chatroom: "Room",
GroupOwner: "false",
SenderCallsign: "Alpha",
ChatGrps: []cotlib.ChatGrp{
{ID: "Room", UID0: "AlphaUID", UID1: "BravoUID"},
},
},
Marti: &cotlib.Marti{Dest: []cotlib.MartiDest{{Callsign: "Bravo"}}},
Remarks: &cotlib.Remarks{
Source: "Example.Alpha",
To: "Room",
Text: "Hello team",
},
}
out, _ := evt.ToXML()
Note: the groupOwner attribute is mandatory for TAK chat messages. It must be
present for schema validation to succeed when using the TAK chat format.
Delivery or read receipts can be sent by populating Detail.ChatReceipt with
the appropriate Ack, ID, and MessageID fields.
Validator Package
The optional validator subpackage provides schema checks for common detail
extensions. validator.ValidateAgainstSchema validates XML against embedded
XSD files. Event.Validate automatically checks extensions such as
__chat, __chatReceipt, __group, __serverdestination, __video,
attachment_list, usericon, and the drawing-related details using these
schemas. All schemas in this repository's takcot/xsd directory are embedded
and validated, including those like Route.xsd that reference other files.
Type Validation and Catalog
The library provides comprehensive type validation and catalog management:
package main
import (
"errors"
"fmt"
"log"
"github.com/NERVsystems/cotlib"
)
func main() {
// Register a custom CoT type
if err := cotlib.RegisterCoTType("a-f-G-U-C-F"); err != nil {
log.Fatal(err)
}
// Validate a CoT type
if err := cotlib.ValidateType("a-f-G-U-C-F"); err != nil {
if errors.Is(err, cotlib.ErrInvalidType) {
log.Fatal(err)
}
}
// Look up type metadata
fullName, err := cotlib.GetTypeFullName("a-f-G-E-X-N")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Full name: %s\n", fullName)
// Output: Full name: Gnd/Equip/Nbc Equipment
// Get type description
desc, err := cotlib.GetTypeDescription("a-f-G-E-X-N")
if err != nil {
log.Fatal(err)
}
fmt.Printf("De
