Skill Format Reference
Every skill is a directory under /sdcard/atak/custos/skills/<group>.<name>/ containing a SKILL.md file with YAML frontmatter and one or more .lua script files.
File structure
custos.markers/
SKILL.md
place_marker.lua
find_items.lua
delete_markers.lua
The directory name must match <group>.<name> from the frontmatter.
SKILL.md frontmatter
---
group: custos
name: markers
description: Place, find, and delete map markers
script_paths:
- custos.markers/place_marker.lua
- custos.markers/find_items.lua
- custos.markers/delete_markers.lua
- custos.tactical_picture/get_self_position.lua
tags:
- markers
- map
- navigation
scope: all
examples:
- "place a marker at 38.9, -77.0"
- "drop a hostile marker"
- "find all friendly markers"
- "mark this position"
---
| Field | Type | Required | Meaning |
|---|---|---|---|
group |
string | yes | First half of the skill ID (typically custos) |
name |
string | yes | Second half of the skill ID |
description |
string | yes | One-line description shown in the agent's system prompt |
script_paths |
list[string] | yes | Paths to Lua files (full paths from the skills root directory) |
tags |
list[string] | no | Keywords used by the skill selector for matching |
scope |
string | no | all (default) or orchestrator |
examples |
list[string] | no | Representative user queries for this skill (improves retrieval accuracy) |
template |
string | no | Extra block injected into the system prompt when this skill is selected |
Script paths
script_paths are paths from /sdcard/atak/custos/skills/, not from the current directory. This lets a skill reference scripts that live in another skill:
script_paths:
- custos.markers/place_marker.lua # script in this skill
- custos.tactical_picture/get_self_position.lua # script from another skill
If you delete a skill whose scripts are referenced by other skills, those dependent skills will fail to load.
Markdown body
Everything after the YAML frontmatter is markdown. The agent sees this text when the skill is selected, so use it to:
- Explain when the skill should be used
- Document rules or assumptions
- Show examples
- Warn about pitfalls
# Markers
Tools for placing, finding, deleting, and querying markers and map items
on the ATAK map.
## Rules
- Always confirm with the operator before deleting more than 5 markers.
- Use the CoT type a-h-G for hostile, a-f-G for friendly, a-n-G for neutral.
Scopes
scope: orchestrator
Skills with scope: orchestrator are only available to the top-level agent, not to specialist sub-agents. This prevents sub-agents from recursively delegating. Default is scope: all.
Examples
examples:
- "place a marker at 38.9, -77.0"
- "drop a hostile marker"
- "find all friendly markers"
- "mark this position"
Example queries improve skill selection accuracy by matching how operators actually phrase requests. Write 3-5 examples per skill covering varied phrasing -- include the way a soldier would say it on comms, not just formal descriptions.
Template
template: |
When responding about marker operations, always:
- Confirm coordinates in DD format
- Reference markers by callsign, never by UID
The template block is inserted into the system prompt when this skill is selected. Useful for skill-specific style guidance, required output formats, or domain conventions.
LDoc annotations on Lua scripts
Inside each .lua file, functions with a @tool annotation become callable agent tools. The annotation block lives in a Lua comment directly above the function:
--- One-line summary
-- @tool tool_name
-- @description Longer description used by the LLM to decide when to call this
-- @tparam string param_name What this parameter is for
-- @tparam number [optional_param=42] Optional with default value
-- @tparam string [type=a-f-G] Optional with default
-- @impact PROCEDURAL
function tool_name(params)
-- params.param_name and params.optional_param available
return { status = "success" }
end
Annotations
| Annotation | Meaning |
|---|---|
@tool <name> |
Registers this function as an agent tool. Must match the function name. |
@description <text> |
One-sentence description shown to the LLM |
@tparam <type> <name> <text> |
Required parameter |
@tparam <type> [<name>=<default>] <text> |
Optional parameter with default |
@impact <level> |
One of READ_ONLY, INFORMATIONAL, PROCEDURAL, SIGNIFICANT, STRATEGIC, LETHAL |
Functions without a @tool annotation are still callable from other Lua functions in the same skill, but the agent never sees them. Use this for helper functions.
Parameter types are documentation for the LLM -- they are not enforced at runtime.
Impact levels
| Level | Meaning | Approval gate |
|---|---|---|
READ_ONLY |
Query, no side effects | No |
INFORMATIONAL |
Logging or memory writes | No |
PROCEDURAL |
Single user-visible action | No (by default) |
SIGNIFICANT |
Multi-step or harder-to-reverse action | Yes |
STRATEGIC |
Coarse / high-impact actions like package distribution, comms broadcasts, or beacon activation | Yes |
LETHAL |
Reserved for actions with irreversible kinetic consequences | Yes |
Unrecognized values fall back to PROCEDURAL with a warning in logcat — match one of the six names exactly.
Tool result format
Return a Lua table from the tool function. It is serialized to JSON and fed back to the agent:
return {
status = "success", -- or "error" or "partial"
result = ..., -- the actual payload
}
If the tool throws an error, the runtime automatically returns { status = "error", error = <message> }.