Authoring Detections
Use a coding agent with the nanodac MCP server to draft, validate, and ship YAML detections to your nano deployment
Authoring Detections with a Coding Agent
The hosted nano product uses pivt AI to draft detection rules from natural language and tune them against historical data. In the OSS build you replace pivt with your coding agent + the nanodac MCP server, using rules as the example corpus.
This page assumes you've completed Setup — nanodac is installed, the MCP server is wired into your agent, and ~/nano-workspace/rules/ is cloned.
Detection file shape (refresher)
nanodac detections are YAML frontmatter with an nPL search body. One file per detection. Example structure:
---
title: brute_force_ssh
description: Detects SSH brute force attempts from a single source IP
author: security-team
severity: high
mode: staging # staging | live
detection_mode: scheduled # scheduled | streaming
schedule: "*/5 * * * *"
lookback: 15m
mitre_tactics: TA0006
mitre_techniques: T1110
risk_score: auto
risk_entity: src_ip
tags:
- authentication
- brute_force
ai_triage_hints:
ignore_when:
- "Source IP is a known security scanner"
- "User is a service account with expected auth patterns"
suspicious_when:
- "Multiple usernames targeted from same IP"
- "Activity occurs outside business hours"
context: "SSH brute force can trigger on legitimate password recovery attempts."
---
source_type=ssh_logs
| where action="login_failed"
| stats count() as attempts, values(user) as targeted_users by src_ip
| where attempts > 10The rules/ repo is organized by MITRE tactic — credential_access/, lateral_movement/, execution/, etc. Browse it for canonical examples; the agent will pull from these when drafting.
ai_triage_hints is still meaningful in the OSS build — even without pivt's auto-triage, the hints serve as inline documentation for analysts and as guidance for any downstream AI you wire in (your own LLM, a SOAR rule engine, or an agent investigating an alert).
End-to-end workflow
Step 1: Describe what you want to detect
Ask the agent in plain English. The more specific, the better:
Draft a detection for AWS CloudTrail events showing an IAM user creating an access key for a different user. Use
~/nano-workspace/rules/credential_access/for tone and structure. MITRE T1098 (Account Manipulation), severity high, scheduled every 5 minutes with a 15-minute lookback. File it underdetections/credential_access/.
The agent will:
- Read 2–3 existing rules in
credential_access/for shape - Look up CloudTrail field names (it'll consult
parsers/parsers/aws_cloudtrail/if needed) - Draft
detections/credential_access/iam_access_key_for_other_user.yaml
Review the draft. Common things to fix:
- Field names — make sure they match what your
aws_cloudtrailparser actually emits mode— should bestagingfor any new detection;liveis reserved for reviewed and tuned rulesrisk_score/risk_entity— should reflect the entity that's actually risky (oftensrc_iporuser, notdest_host)
Step 2: Validate
The nanodac MCP server exposes a validate tool. Ask the agent:
Validate the new detection.
Behind the scenes this runs nanodac validate against the YAML — checks frontmatter schema, parses the nPL body, and surfaces any errors. If you don't have MCP wired up, run it manually:
nanodac validateFix any reported errors and re-run. Validation is fast — there's no reason to skip it.
Step 3: Test against historical data
Before pushing live, dry-run the detection against real events in your nano deployment:
nanodac test detections/credential_access/iam_access_key_for_other_user.yamlOr via the agent: "Test this detection — show me the matches it would have produced over the last 7 days."
nanodac test runs the search body against your deployment's historical data and returns the matching events. Use this to:
- Confirm the rule fires when it should (find a known-good event and verify it matches)
- Estimate noise — if the detection would have produced 500 alerts in the last week, it needs more
whereclauses
If the result looks noisy, ask the agent: "That's too many matches — most are service accounts. Add a where user NOT MATCHES \"svc-.*\" filter and re-test."
Step 4: Open a PR
Detection-as-code's whole point is review-before-deploy. Don't skip the PR:
git checkout -b detection/iam-access-key-for-other-user
git add detections/credential_access/iam_access_key_for_other_user.yaml
git commit -m "Add detection: IAM access key created for another user"
git push -u origin detection/iam-access-key-for-other-user
gh pr create --title "Detection: IAM access key for other user" --body "..."The agent can run all of these for you. A reviewer should look at:
- nPL correctness — does the search actually match the described behavior?
- Field name accuracy — do the fields exist in the parsed events?
ai_triage_hints— are the ignore/suspicious lists realistic?- Severity calibration — is
highappropriate, or should this bemedium?
Step 5: Sync to nano
Once merged, CI (or you, locally) runs nanodac sync to push the detection to your nano deployment. The shipped GitHub Action template at .github/workflows/detection-sync.yml (created by nanodac init) does this automatically on merge to main.
Manual sync:
git checkout main && git pull
nanodac sync --dry-run # preview
nanodac sync # applyThe detection will land in staging mode (per its frontmatter). After it runs cleanly for a few days with the expected match volume, edit the YAML to set mode: live, open another PR, and re-sync.
Iteration patterns
Tuning a noisy detection. Run nanodac test to get the noisy matches → paste a few false-positive events to the agent → ask it to propose additional where clauses → re-test. Loop until the false-positive rate is acceptable.
Porting an existing rule from another SIEM. Show the agent the source rule (Sigma, Splunk SPL, KQL) and a 1–2 closest nano examples from rules/. Ask: "Port this rule to nano nPL format, using these examples for structure." Validate before trusting the output.
Bulk-importing a tactic. Point the agent at a MITRE technique and ask it to draft 3–5 candidate detections covering different angles. Treat the output as a starting point, not a finished set — review each one individually.
Anti-patterns
- Don't sync directly from your laptop to production. Always go through PR review. The CI-driven sync is there for a reason.
- Don't trust agent-generated
mitre_tactics/mitre_techniquesblindly. Cross-check against attack.mitre.org — agents will sometimes confidently produce technique IDs that don't map to the described behavior. - Don't set
mode: liveon first commit. Always start instaging, watch the match volume for a few days, then promote.
What's next
- Crafting searches — use the agent for ad-hoc hunting, not just scheduled detections
- Detection-as-Code — full nanodac CLI reference
- Risk-Based Alerting — how
risk score=chains compose into alerts