Custom packs
Custom packs
A custom pack is a query pack you wrote and uploaded — Mimir stores the YAML in the database, parses it, and schedules its queries on every connected agent. Custom packs are the right tool for fleet-wide investigations you want to run forever rather than on demand: a shared playbook for finding suspicious autoruns, a quarterly check on specific Windows registry keys, a continuous inventory of installed software.
If you only need to run a query once, use Run a query. If the query needs to be a recurring fleet-wide check, this is the path.
What you get
Custom packs live alongside bundled packs on the Packs list. The differences a user sees:
- The small source label on the list row and the detail header reads
custominstead ofbundled. - The detail page renders a Source YAML card at the bottom — the full text of the YAML you uploaded, monospace, for read-only inspection. Bundled packs never show this card; they’re emitted from the binary and have no editable representation.
Everything else — the health dot, the schedule cadence, the enabled pill, the per-query table on the detail page — is identical.
Why use one
Three patterns:
- Codify a playbook. You wrote a great saved query and re-run it weekly. Promote it into a scheduled pack so the fleet answers continuously instead of you re-running it.
- Fleet-wide compliance evidence. A pack with a recurring schedule
and a clear name (
Quarterly autoruns audit) gives auditors a durable record: “every host checked in with the result every N hours, here are the rows.” - Bespoke detection. You suspect a particular registry path is touched by a threat actor your team is tracking. Codify the per-OS query into a custom pack instead of hand-running it.
Authoring the YAML
Custom packs share osquery’s pack format. The minimum useful shape:
name: My Packdescription: One-line summary that shows up on the list page.queries: - name: example sql: SELECT * FROM users LIMIT 1 interval: 3600 platform: all description: Optional per-query description.Field notes:
nameis the human-readable label that shows on the list page and on the detail header.descriptionis the optional one-liner between the header strip and the 24h counters.queries[].sqlis the osquery SQL the agent runs. The same table availability rules as Run a query apply: pick aplatformthat matches the tables you’re using.queries[].intervalis the cadence in seconds. Lower numbers mean more rows ingested per day — keep an eye on the 24h counters after you upload.queries[].platformcan beall,windows,linux,macos, orbsd. The detail page renders this as a friendly label.
Bundled packs in your deployment are good shape references — open their detail pages to see how a known-working pack lays out its queries and intervals.
Uploading
- From the Packs list, click + Upload Pack in the header. The button is admin-only.
- The upload modal opens with a placeholder YAML in the textarea so you can see the expected shape.
- Paste your YAML. The textarea is monospace and accepts up to several hundred KB of YAML — plenty for most packs.
- Click Upload. The server validates the YAML and parses it.
- On success, a toast confirms (
Pack "<name>" uploaded), the modal closes, and the list refreshes to show your new pack at the top.
Validation errors
If the server rejects the upload, the modal stays open and renders each error in a red-bordered list under the textarea:
queries[0].sql: requiredqueries[1].interval: must be a positive integerFix the lines the server flagged and re-click Upload. The textarea content is preserved across rejected attempts so you don’t lose your work.
If the YAML is structurally invalid (a parser error rather than a
schema error), the modal shows a single line such as Upload failed: yaml: unmarshal errors. The fix is usually a missing colon or wrong
indentation; paste the YAML into any linter to spot the line, then
re-submit.
Editing a custom pack
There is no in-place YAML edit. To change a custom pack’s contents:
- Update the YAML locally.
- Open the existing pack from the list and click Delete.
- Re-upload with the same name (or a new name if you want both versions to coexist temporarily).
This is deliberate: a re-upload triggers a full re-parse and re-validation, and avoids the half-applied state a partial edit could produce.
If all you need is to pause the pack, use the Disable toggle on the list page instead.
Deleting a custom pack
Click Delete on the list-page row, or open the detail page and delete from there. A confirmation modal asks you to confirm.
If the pack is referenced by one or more compliance policies, the
server returns a compliance_references error and the UI swaps in a
force-delete dialog listing each policy:
This pack is referenced by 2 compliance policies:
- BitLocker enabled
- Screen lock under 5 minutes
Force-deleting will disable these policies. This cannot be undone.
Click Cancel to back out, or Force Delete to proceed. The force-delete path disables every referencing policy in the same operation; the policies don’t auto-re-enable when you re-upload a replacement pack. If you want to keep the policies enabled, delete or recreate them first against a different pack.
Permissions
Uploading, editing (via re-upload), and deleting custom packs is admin-only. Listing and viewing details is open to any signed-in user, the same as for bundled packs.
Troubleshooting
The upload modal accepted my YAML but the pack never appears in the list. The upload responded with an error you missed in a closed toast. Re-open the modal — if the textarea is empty the upload completed and there’s a non-list issue (a race with the refresh that masked the new row). Reload the page; the pack should appear if the upload truly succeeded.
Force-delete prompts even though I haven’t set up any compliance policies. Someone else on your team has — the policy table is fleet-wide. Read the listed policy names. If they’re not yours, talk to your team before force-deleting; the policies are downstream of the pack but may be load-bearing for someone else’s work.
A custom pack’s health dot stays red on “Silent failure.” The agents are running it but returning no rows. Open the detail page, look at the per-query Last Result column. A query whose Last Result is recent but whose Rows 24h is zero is the silent-failure case — the SQL is valid (the agent ran it) but its WHERE clause is filtering everything out, or the underlying table moved on a recent OS update. Re-upload with corrected SQL.
Where to next
- Bundled packs — the read-only set Mimir ships with, and the structural differences from custom packs.
- Query packs overview — the list page, the health dot, and the 24h counters that surface a misbehaving pack.
- Run a query — when “do this once” is closer to your need than “do this forever.”