Setup
Install the nanodac CLI from npm and wire up your coding agent with the nanodac MCP server
Setup
To make a coding agent useful against nano, give it three things:
- Reference material: local clones of the
parsersandrulesrepositories so the agent has real examples to learn from - A way to talk to nano: the
nanodacCLI and its MCP server, which expose detection sync, validation, and search as agent-callable tools - Repo-specific instructions: a
CLAUDE.md(orAGENTS.md) file that tells the agent your conventions
This page walks through all three.
Step 1: Clone the reference repositories
Pick a workspace directory and clone both reference repos as siblings. The exact layout doesn't matter (the agent discovers them by path), but keeping them as siblings of your detections repo is the convention used in these docs.
mkdir -p ~/nano-workspace && cd ~/nano-workspace
git clone https://github.com/nano-rs/parsers.git
git clone https://github.com/nano-rs/rules.gitYou should end up with:
~/nano-workspace/
├── parsers/ # 60+ sample parser.yaml files
└── rules/ # Detection corpus organized by MITRE tacticPull these regularly: the upstream repos are where new vendor support and detection coverage lands first.
Step 2: Install nanodac
nanodac is the CLI that validates detections, syncs them to your nano deployment, and exposes those operations to your agent over MCP. It's published to npm as @nano-rs/dac-cli — no clone or build. Install it globally so the nanodac command is on your PATH:
npm install -g @nano-rs/dac-cliOr skip the install and run any command through npx @nano-rs/dac-cli <command>.
Verify:
nanodac --helpStep 3: Create your detections repo
This is where your agent will write. Keep it separate from the reference repos so updates don't conflict with your work.
cd ~/nano-workspace
mkdir my-detections && cd my-detections
git init
nanodac initnanodac init scaffolds:
my-detections/
├── nanodac.config.yaml # API endpoints + sync defaults
├── detections/ # Your YAML detections live here
└── .github/workflows/ # Optional CI for validate + syncEdit nanodac.config.yaml to point at your nano deployment:
apiUrl: https://your-nano.example.com:3001
searchUrl: https://your-nano.example.com:3002
detectionsDir: ./detections
defaultSeverity: medium
defaultMode: staging
sync:
deleteOrphans: false
confirmDestructive: trueSet the API key in your shell environment (do not commit it):
export NANOSIEM_API_KEY="your-api-key-here"Generate the key from your nano deployment under Settings → API Keys, scoped to the permissions in API key permissions below.
Step 4: Wire up the nanodac MCP server
The MCP server gives your agent direct, typed access to nano: it can list detections, run validation, fetch search results, and trigger syncs without you copy-pasting CLI output.
Drop this into .mcp.json (or mcp-config.json for Cursor) at the root of your detections repo:
{
"mcpServers": {
"nanodac": {
"command": "npx",
"args": ["-y", "@nano-rs/dac-mcp-server"],
"env": {
"NANOSIEM_API_URL": "https://your-nano.example.com:3001",
"NANOSIEM_API_KEY": "${NANOSIEM_API_KEY}",
"NANOSIEM_SEARCH_URL": "https://your-nano.example.com:3002"
}
}
}
}The MCP server ships as @nano-rs/dac-mcp-server; npx resolves it on launch. The ${NANOSIEM_API_KEY} reference reads from the shell environment at agent startup, so your API key never gets written to disk. (Prefer no per-launch resolution? npm i -g @nano-rs/dac-mcp-server and set "command": "nanodac-mcp" with no args.)
Restart your agent. In Claude Code, run /mcp to confirm nanodac shows as connected. In Cursor, the MCP panel will list it under Available Servers.
Step 5: Give the agent your conventions
Without instructions, an agent will produce plausible-looking output that drifts from your team's style. A short instructions file fixes this.
Create CLAUDE.md (or AGENTS.md, or both; they can be identical) at the root of your detections repo:
# Detection Engineering — agent instructions
## Reference repositories
When asked to author or modify detections, parsers, or searches, consult:
- `~/nano-workspace/parsers/parsers/` — sample parsers in YAML+VRL format
- `~/nano-workspace/rules/` — sample detections organized by MITRE tactic
- https://github.com/nano-rs/nanodac/tree/main/examples — canonical detection examples
- `/agents/detection-as-code/parsers`, `/agents/detection-as-code/detections`, `/agents/detection-as-code/search` in nano docs
Always read at least 2 existing examples before drafting a new one.
## Detection conventions
- New detections start with `mode: staging` — never `live` until reviewed
- Always include `mitre_tactics` and `mitre_techniques`
- Always include `ai_triage_hints` with `ignore_when` and `suspicious_when` lists
- Use `risk score=` instead of bare `where` for severity tuning
- File goes under `detections/<tactic>/<descriptive_name>.yaml`
## Workflow
1. Draft the detection in a new branch
2. Run `nanodac validate` (via the MCP `validate` tool)
3. Run `nanodac test <file>` to sanity-check against historical data
4. Open a PR — never push to main directly
5. After merge, CI runs `nanodac sync` to deployTune this to your team. The agent will read it on every session start.
API key permissions
nanodac authenticates to the nano API with the key in NANOSIEM_API_KEY (sent as the X-API-Key header). A nano key carries an explicit permission list set when you create it — no role inheritance — and the backend checks every request against it, so scope the key to least privilege. nanodac's surface splits three ways:
- nano API tools — gated by the permissions below.
- GitHub tools (
create_issue,list_issues,create_pull_request) — gated by yourghCLI authentication (aGITHUB_TOKEN/GH_TOKENwith issue + PR scope on your detections repo), not a nano permission. - Local git / filesystem tools (
create_branch,commit_and_push,write_detection_file,sync_repo,get_current_branch,get_schema) — no permission at all.
If the backend runs with AUTH_ENABLED=false (development only), permission checks are skipped and any key works. Never rely on that in production.
nano API tools — permissions
| Capability | Permissions | Access |
|---|---|---|
Detections — read / validate / test (list_detections, get_detection, test_detection, validate_detection) | detections:view | read |
Detection authoring (create_detection, update_detection) | detections:create, detections:edit, detections:promote ¹ | write |
Lifecycle (promote_detection, demote_detection, trigger_detection) | detections:promote | write |
Ad-hoc query test (test_query) | detections:create ² | read |
Export (export_detections) | detections:export | read |
Search (search) | search:execute | read |
Rule repositories (list_repositories, browse_repository, get_coverage, convert_sigma ³) | rule_repositories:view | read |
Rule repositories — write (sync_repository, import_rule) | rule_repositories:sync, rule_repositories:import | write |
¹ update_detection additionally needs detections:promote when a change touches mode / detection_mode / realtime_enabled / schedule_cron or lowers severity; plain edits need only detections:edit. ² test_query (POST /api/rules/test) requires detections:create; the read-only test_detection / validate_detection need only detections:view. ³ convert_sigma is an enterprise-only feature.
Minimal vs full key
Validate, test, and read — the typical CI / authoring-review key (the local git tools work with no nano permission):
[ "detections:view", "detections:create", "search:execute", "rule_repositories:view" ]detections:create is included only because the test_query tool needs it — drop it if you stick to test_detection / validate_detection.
Full detection-as-code — author, promote, export, and sync/import from rule repositories:
[
"detections:view", "detections:create", "detections:edit", "detections:promote",
"detections:export", "search:execute",
"rule_repositories:view", "rule_repositories:sync", "rule_repositories:import"
]The GitHub tools still need their own gh token; neither key above grants any GitHub access.
Create a scoped key
Under Settings → API Keys in nano, create a key with the permissions above — you can only grant permissions your own account holds. Or call POST /api/api-keys (the caller needs apikeys:create) and export the result as NANOSIEM_API_KEY.
Verify the full setup
Ask your agent:
List the detections currently configured in nano.
If MCP is wired correctly, the agent will call the nanodac MCP server's list tool and return a real list from your deployment. If it asks you to run a CLI command instead, the MCP connection isn't live: re-check .mcp.json and that NANOSIEM_API_KEY is exported in the shell that launched the agent.
What's next
- Authoring parsers: first end-to-end parser walkthrough
- Authoring detections: first end-to-end detection walkthrough
- Crafting searches: natural-language hunting