automation
Create recurring agent tasks — scheduled checks, perimeter monitors, and event-driven watchers that run automatically
Skill by nimbusxr
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/nimbusxr-automation
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: agent-building
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/automation
What's inside
- Skill name
automation- Description
- Create recurring agent tasks — scheduled checks, perimeter monitors, and event-driven watchers that run automatically
- License
- MIT
- Instructions
- 110 lines in SKILL.md · view on GitHub
Agent Skills spec issues
- name: "automation" does not match folder "custos.automation"
Files (3)
- SKILL.md
- manage_automation.lua
- write_automation.lua
SKILL.md (first lines)
You create and manage automations for the CUST/OS operator. An automation is a `.lua` file with a top-level `function run(ctx)` that the scheduler invokes when the trigger fires. Automations execute as deterministic Lua — the LLM is not touched automatically.
## Core rule: automations never call the LLM implicitly
Every automation is just Lua. If the task needs LLM reasoning, the `run()` body MUST explicitly call `tools.call("delegate", {agent_name = "...", task = "..."})`. Anything else — checking state, placing markers, playing alerts, sending messages — goes through `tools.call("skill_name", {...})` directly and runs without the LLM.
## How `tools.call` works
Inside `run()`, invoke any registered tool by its **tool name** (NOT its skill ID):
```lua
local pos = tools.call("get_self_position", {})
local hostiles = tools.call("find_nearby", { lat = pos.lat, lon = pos.lon, radius_m = 300, affiliation = "hostile" })
tools.call("play_tone", { type = "alarm" })
```
Arguments are a Lua table; return value is a Lua table with the tool's result.
### Tool names ≠ skill IDs
This trips up every LLM. They are different things:
- **Skill IDs** are dotted namespaces like `custos.tactical_picture`, `custos.markers`, `custos.fires`. They group related tools.
- **Tool names** are short identifiers like `get_picture`, `place_marker`, `hostile_list`. They're the `@tool` annotation in a `.lua` file and the thing you pass to `tools.call`.
You do NOT call `tools.call("custos.tactical_picture", ...)`. You call `tools.call("get_picture", ...)`.
Common hallucination to avoid: inventing a tool name by combining words from the skill ID. The skill `custos.tactical_picture` does **not** expose a tool called `get_tactical_picture` — it exposes `get_picture`. The skill `custos.fires` does **not** expose `get_fires` — it exposes `hostile_list` and `danger_close_check`.
### Before writing an automation: verify tool names
If you're not 100% sure a tool exists by the name you're about to use, call `discover_api(query="<topic>")` from `custos.skill_creator` first to enumerate the real tool names. `write_automation` validates every `tools.call(...)` reference in the body before writing — unknown tool names are rejected with an error listing them, so hallucinated names will fail at write time, not at runtime.
## The `run(ctx)` signature
The parameter name matches the trigger type (self-documenting convention — Lua doesn't enforce names):
- **Schedule (cron or one-shot)**: `function run(schedule)` → `ctx = { fired_at, cron }`
- **Interval (duration)**: `function run(interval)` → `ctx = { fired_at, interval }`
- **Event (broadcast)**: `function run(event)` → `ctx = { fired_at, action, cot_type, uid, lat, lon, callsign, hae, how, cot_xml, extra_* }`
`fired_at` is milliseconds since epoch. For event triggers, additional fields come from the parsed broadcast intent (CoT XML, extras, etc.).
## Examples
**Interval — perimeter monitor:**
```
write_automation(
name = "perimeter_monitor",
trigger = "15s",
body = [[
local pos = tools.call("get_self_position", {})
local result = tools.call("find_nearby", { lat = pos.lat, lon = pos.lon, radius_m = 300, affiliation = "hostile" })
if result.count > 0 then
tools.call("play_tone", { type = "alarm" })
end
]],
description = "300m hostile perimeter sweep every 15 seconds",
session = "ISOLATED"
)
```
**Schedule — morning SITREP with LLM reasoning via delegate:**
```
write_automation(
name = "morning_sitrep",
trigger = "0 6 * * *",
body = [[
local result = tools.call("delegate", {
agent_name = "orchestrator",
task = "Generate a comprehensive SITREP from the current tactical picture."
})
tools.call("speak_alert", { message = result.response })
]],
description = "Daily 0600 SITREP",
session = "MAIN"
)
```
**Event — hostile CoT alert with inline filter:**
```
write_automation(
name = "hostile_alert",
trigger = "com.atakmap.android.maps.COT_RECD",
body = [[
if not (event.cot_type and event.cot_type:find("a-h-")) then return end
tools.call("speak_alert", { message = "Hostile: " .. (event.callsign or "unknown") })
]],
description = "Fire when a hostile CoT is received",
session = "ISOLATED"
)
```
## Filter and debounce patterns
- **Filter** — put a guard clause at the top of `run()`: `if not (event.cot_type and event.cot_type:find("a-h-")) then return end`. No separate `@filter` annotation.
- **Debounce** — if truly needed, track `last_fired_at` in the memory service: `local last = memory:get("myauto_last") or 0; if fired_at - last < 60000 then return end; memory:put("myauto_last", fired_at)`. Rarely needed — deterministic Lua is cheap.
## Managing automations
Use `manage_automation` to list, toggle, or delete existing automations.
## Critical rules
- Always use `write_automation` to create automations — never write raw `.lua` files manually.
- Prefer deterministic `tools.call` chains over `delegate`. Only delegate when the task actually requires reasoning over variable inputs.
- For event triggers, use `discover_api(query="intents")` to verify the broadcast action exists before creating.
- Use `session = "ISOLATED"` (the default) for background automations so they don't pollute the operator's active conversation.From nimbusxr/custos, MIT.
More from nimbusxr/custos
- 0.459score
drawing
nimbusxr
Draw shapes on the map — polygons, rectangles, circles, and polylines
SkillDFreshness: D★ 7Claude Code +9 - 0.456score
agents
nimbusxr
Delegate tasks to specialist agents
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
bullseye
nimbusxr
Range/bearing from reference points — standard targeting protocol
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
bloodhound
nimbusxr
Track targets with bearing, distance, speed, and intercept data
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
casualty
nimbusxr
Generate 9-line MEDEVAC requests, casualty cards, HLZ marking, and emergency beacons
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
fires
nimbusxr
Call for fire, hostile tracking, danger close calculations, and munitions data
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
geofence
nimbusxr
Create and monitor geofences for perimeter security and proximity alerts
SkillDFreshness: D★ 7Claude Code +9 - 0.451score
attachments
nimbusxr
Attach files to map items — photos, documents, reports
SkillDFreshness: D★ 7Claude Code +9 - 0.451score
bpha
nimbusxr
Battle Position Holding Area — defensive planning graphics
SkillDFreshness: D★ 7Claude Code +9 - 0.451score
geocoding
nimbusxr
Convert between street addresses and coordinates
SkillDFreshness: D★ 7Claude Code +9 - 0.451score
alerts
nimbusxr
Send notifications, play tones, and speak alerts
SkillDFreshness: D★ 7Claude Code +9 - 0.450score
comms_status
nimbusxr
Monitor network health, TAK server connectivity, and active feeds
SkillDFreshness: D★ 7Claude Code +9
Signals
- Stars
- 7
- Forks
- 0
- Open issues
- 1
- Last commit (this folder)
- Apr 21, 2026 (6 months ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/nimbusxr/custos
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from nimbusxr
- 0.459score
drawing
nimbusxr
Draw shapes on the map — polygons, rectangles, circles, and polylines
SkillDFreshness: D★ 7Claude Code +9 - 0.456score
agents
nimbusxr
Delegate tasks to specialist agents
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
fires
nimbusxr
Call for fire, hostile tracking, danger close calculations, and munitions data
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
bloodhound
nimbusxr
Track targets with bearing, distance, speed, and intercept data
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
casualty
nimbusxr
Generate 9-line MEDEVAC requests, casualty cards, HLZ marking, and emergency beacons
SkillDFreshness: D★ 7Claude Code +9 - 0.454score
geofence
nimbusxr
Create and monitor geofences for perimeter security and proximity alerts
SkillDFreshness: D★ 7Claude Code +9
Cite this page
automation skill. Agent Mart. https://agentmart.dev/skills/nimbusxr-automation (last updated 2026-10-24)