detectkit 0.44.0__tar.gz → 0.45.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. {detectkit-0.44.0/detectkit.egg-info → detectkit-0.45.0}/PKG-INFO +1 -1
  2. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/__init__.py +1 -1
  3. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/CLAUDE.section.md +19 -9
  4. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/rules/alerting.md +3 -5
  5. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/rules/overview.md +1 -2
  6. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/rules/project.md +1 -2
  7. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/skills/dtk-autotune/SKILL.md +11 -2
  8. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md +20 -5
  9. detectkit-0.45.0/detectkit/cli/assets/claude/skills/dtk-tune/SKILL.md +184 -0
  10. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/init_claude.py +1 -1
  11. {detectkit-0.44.0 → detectkit-0.45.0/detectkit.egg-info}/PKG-INFO +1 -1
  12. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit.egg-info/SOURCES.txt +1 -0
  13. {detectkit-0.44.0 → detectkit-0.45.0}/LICENSE +0 -0
  14. {detectkit-0.44.0 → detectkit-0.45.0}/MANIFEST.in +0 -0
  15. {detectkit-0.44.0 → detectkit-0.45.0}/README.md +0 -0
  16. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/__init__.py +0 -0
  17. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/__init__.py +0 -0
  18. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/base.py +0 -0
  19. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/branding.py +0 -0
  20. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/email.py +0 -0
  21. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/factory.py +0 -0
  22. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/mattermost.py +0 -0
  23. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/slack.py +0 -0
  24. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/telegram.py +0 -0
  25. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/channels/webhook.py +0 -0
  26. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/__init__.py +0 -0
  27. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/_base.py +0 -0
  28. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
  29. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/_decision.py +0 -0
  30. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
  31. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/_recovery.py +0 -0
  32. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/_replay.py +0 -0
  33. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/_types.py +0 -0
  34. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
  35. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/__init__.py +0 -0
  36. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/_base.py +0 -0
  37. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/_types.py +0 -0
  38. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/autotuner.py +0 -0
  39. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/config_emitter.py +0 -0
  40. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/crossval.py +0 -0
  41. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/detector_select.py +0 -0
  42. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/distribution.py +0 -0
  43. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/grid_search.py +0 -0
  44. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/labels.py +0 -0
  45. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/result.py +0 -0
  46. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/runner.py +0 -0
  47. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/scoring.py +0 -0
  48. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/seasonality_search.py +0 -0
  49. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/settings.py +0 -0
  50. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/autotune/window_select.py +0 -0
  51. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/__init__.py +0 -0
  52. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/_output.py +0 -0
  53. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/rules/autotune.md +0 -0
  54. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/rules/cli.md +0 -0
  55. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/rules/detectors.md +0 -0
  56. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/rules/metrics.md +0 -0
  57. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md +0 -0
  58. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md +0 -0
  59. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/__init__.py +0 -0
  60. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/autotune.py +0 -0
  61. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/clean.py +0 -0
  62. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/init.py +0 -0
  63. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/run.py +0 -0
  64. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/test_alert.py +0 -0
  65. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/tune.py +0 -0
  66. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/commands/unlock.py +0 -0
  67. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/cli/main.py +0 -0
  68. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/config/__init__.py +0 -0
  69. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/config/metric_config.py +0 -0
  70. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/config/profile.py +0 -0
  71. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/config/project_config.py +0 -0
  72. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/config/validator.py +0 -0
  73. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/core/__init__.py +0 -0
  74. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/core/interval.py +0 -0
  75. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/core/models.py +0 -0
  76. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/__init__.py +0 -0
  77. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/_sql_manager.py +0 -0
  78. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/clickhouse_manager.py +0 -0
  79. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/__init__.py +0 -0
  80. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_alert_states.py +0 -0
  81. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_autotune_runs.py +0 -0
  82. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_base.py +0 -0
  83. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_datapoints.py +0 -0
  84. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_detections.py +0 -0
  85. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_maintenance.py +0 -0
  86. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_metrics.py +0 -0
  87. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_schema.py +0 -0
  88. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/_tasks.py +0 -0
  89. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/internal_tables/manager.py +0 -0
  90. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/manager.py +0 -0
  91. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/mysql_manager.py +0 -0
  92. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/postgres_manager.py +0 -0
  93. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/database/tables.py +0 -0
  94. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/__init__.py +0 -0
  95. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/base.py +0 -0
  96. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/factory.py +0 -0
  97. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/seasonality.py +0 -0
  98. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/statistical/__init__.py +0 -0
  99. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/statistical/_windowed.py +0 -0
  100. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/statistical/iqr.py +0 -0
  101. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/statistical/mad.py +0 -0
  102. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/statistical/manual_bounds.py +0 -0
  103. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/detectors/statistical/zscore.py +0 -0
  104. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/loaders/__init__.py +0 -0
  105. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/loaders/metric_loader.py +0 -0
  106. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/loaders/query_template.py +0 -0
  107. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/__init__.py +0 -0
  108. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/error_dispatch.py +0 -0
  109. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/task_manager/__init__.py +0 -0
  110. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
  111. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/task_manager/_base.py +0 -0
  112. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
  113. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/task_manager/_load_step.py +0 -0
  114. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/task_manager/_types.py +0 -0
  115. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/orchestration/task_manager/manager.py +0 -0
  116. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/reporting/__init__.py +0 -0
  117. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/reporting/assets/report.js +0 -0
  118. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/reporting/builder.py +0 -0
  119. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/reporting/html_report.py +0 -0
  120. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/tuning/__init__.py +0 -0
  121. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/tuning/assets/tune.js +0 -0
  122. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/tuning/config_writer.py +0 -0
  123. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/tuning/html.py +0 -0
  124. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/tuning/payload.py +0 -0
  125. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/tuning/server.py +0 -0
  126. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/utils/__init__.py +0 -0
  127. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/utils/datetime_utils.py +0 -0
  128. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/utils/env_interpolation.py +0 -0
  129. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/utils/json_utils.py +0 -0
  130. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit/utils/stats.py +0 -0
  131. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit.egg-info/dependency_links.txt +0 -0
  132. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit.egg-info/entry_points.txt +0 -0
  133. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit.egg-info/requires.txt +0 -0
  134. {detectkit-0.44.0 → detectkit-0.45.0}/detectkit.egg-info/top_level.txt +0 -0
  135. {detectkit-0.44.0 → detectkit-0.45.0}/pyproject.toml +0 -0
  136. {detectkit-0.44.0 → detectkit-0.45.0}/requirements.txt +0 -0
  137. {detectkit-0.44.0 → detectkit-0.45.0}/setup.cfg +0 -0
  138. {detectkit-0.44.0 → detectkit-0.45.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.44.0
3
+ Version: 0.45.0
4
4
  Summary: Metric monitoring with automatic anomaly detection
5
5
  Author: detectkit team
6
6
  License: MIT
@@ -4,7 +4,7 @@ detectk - Anomaly Detection for Time-Series Metrics
4
4
  A Python library for data analysts and engineers to monitor metrics with automatic anomaly detection.
5
5
  """
6
6
 
7
- __version__ = "0.44.0"
7
+ __version__ = "0.45.0"
8
8
 
9
9
  from detectkit.core.interval import Interval
10
10
  from detectkit.core.models import ColumnDefinition, TableModel
@@ -48,15 +48,25 @@ version — **read the relevant one on demand** instead of guessing:
48
48
  values that need your real connection details) and, optionally, a first alert
49
49
  channel.
50
50
  - **A new metric** — use the **`dtk-new-metric`** skill; it walks the config out
51
- to a YAML file that validates and is ready to run.
52
- - **Tune / pick a detector, or build an alert from scratch and tune it** — use
53
- the **`dtk-autotune`** skill; it gathers seasonality + incidents, runs
54
- `dtk autotune`, and explains the chosen, annotated config (an automatic,
55
- cross-validated search). For **hands-on** tuning instead, `dtk tune` opens a
56
- browser view where you drag the detector's knobs against the real series and
57
- write the result back in place and its **Autotune** mode can run that same
58
- search server-side and re-seed the knobs without leaving the cockpit (see
59
- `cli.md`).
51
+ to a YAML file that validates and is ready to run. A robust starter is enough —
52
+ it's the **sandbox** the user then refines with one of the tuning skills below.
53
+ - **Tune a detector (hands-on, recommended)** — use the **`dtk-tune`** skill: it
54
+ loads some history and opens an interactive browser **cockpit** where the user
55
+ turns the detector's knobs on their **real** series and watches the band,
56
+ anomalies and would-fire alerts recompute live, then **Apply**s the result back
57
+ into the metric YAML in place. It is the **umbrella** for tuning: its **Autotune**
58
+ mode runs the full `dtk autotune` engine **server-side** and re-seeds the knobs,
59
+ and its **Label / Review** modes mark or confirm incidents — so the user can
60
+ auto-search, hand-tune and label in one place. **Prefer this whenever the user
61
+ wants to be in the loop** (see, judge, adjust). This is also how you build an
62
+ alert from scratch and dial it in: scaffold the metric (`dtk-new-metric`), then
63
+ open the cockpit.
64
+ - **Tune a detector (fully automatic)** — use the **`dtk-autotune`** skill: a
65
+ cross-validated **command-line** search (seasonality → detector → params →
66
+ window) that writes an annotated `__tuned_<id>.yml` without touching the
67
+ original. Best for CI or "just pick one for me, I won't look." It runs the same
68
+ engine `dtk-tune`'s Autotune mode does — pick the skill by whether the user wants
69
+ hands-on or hands-off.
60
70
  - **Hit a detectkit bug, or have feedback** — once you've ruled out a local
61
71
  config fix (see the gotchas below), use the **`dtk-feedback`** skill to file a
62
72
  redacted bug report, feature request, or comment as a GitHub issue on the
@@ -164,8 +164,7 @@ config needed. Control it project-wide with `alert_help_url` in
164
164
  - **a URL string** → your own runbook/wiki page instead
165
165
  - **`false`** → hide the link entirely
166
166
 
167
- Per-channel rendering (defaults only; resolved by
168
- `ProjectConfig.resolve_alert_help_url`):
167
+ Per-channel rendering (defaults only; the resolved help URL is rendered per channel as follows):
169
168
 
170
169
  - **Slack / Mattermost / generic webhook** — a clickable `How to read this alert`
171
170
  label in the compact `Links` field (alongside `Dashboard` + any extra links),
@@ -185,7 +184,7 @@ mirrors `{dashboard_url}` / `{dashboard_line}`. See the template table below.
185
184
 
186
185
  With no custom `template`, each channel renders a structured, branded message
187
186
  (alert-centric: the rule that fired leads, the anomaly value is evidence). The
188
- shared value computation lives in one place (`BaseAlertChannel.build_context`),
187
+ shared value computation lives in one place,
189
188
  so templates and native rendering stay consistent. Every alert title/headline
190
189
  leads with a colored **status circle** — 🔴 anomaly, 🟢 recovery, 🟡 no-data,
191
190
  🔵 pipeline error — so the status reads from color alone. It also leads with the
@@ -241,8 +240,7 @@ Latest reading** fields bound the span. Labels are self-describing so the onset
241
240
  isn't misread as the alert-fire moment: **Anomaly began** is the resolved onset,
242
241
  **not** when the alert fired. Recovery shows the fuller **began → fired →
243
242
  recovered** timeline (`Incident lasted …`), where **Alert fired** =
244
- `onset + (consecutive_required − 1) × interval` (computed in `build_context`,
245
- exposed as `{fired_display}`, omitted when the run is capped). The true
243
+ `onset + (consecutive_required − 1) × interval` (exposed as `{fired_display}`, omitted when the run is capped). The true
246
244
  streak/onset is resolved only when an alert fires/clears (a bounded lookback over
247
245
  the detection history; a run older than the window shows `over …`), so the hot
248
246
  no-alert path stays cheap. Exposed to templates as `{anomaly_lead}` /
@@ -114,6 +114,5 @@ series, watch the band recompute live, then write the config back into the metri
114
114
 
115
115
  ## Authoritative sources
116
116
 
117
- The shipped detectkit docs (`docs/` in the repo, or
118
- <https://dtk.pipelab.dev>) and the `CHANGELOG.md` are authoritative for
117
+ The detectkit docs at <https://dtk.pipelab.dev> and the project changelog are authoritative for
119
118
  behavior. These rule files summarize them for the installed version.
@@ -45,8 +45,7 @@ overrides it; unset → a built-in `0.5`. Tuning-only — it never touches the p
45
45
  ### `alert_help_url` — "How to read this alert" link
46
46
 
47
47
  Every default-rendered alert on every channel carries a `How to read this alert`
48
- link for non-operator stakeholders. Tri-state, resolved by
49
- `ProjectConfig.resolve_alert_help_url`:
48
+ link for non-operator stakeholders. Tri-state:
50
49
 
51
50
  - **unset / null** (default) → the official detectkit guide
52
51
  (`https://dtk.pipelab.dev/guides/reading-alerts/`).
@@ -20,6 +20,14 @@ have them, otherwise an unsupervised objective), and writes a ready-to-run
20
20
  config named `<metric>__tuned_<id>` whose comment header explains every
21
21
  decision. Each run is recorded in the `_dtk_autotune_runs` table.
22
22
 
23
+ **This skill is the fully-automatic, command-line path** — best for CI or when the
24
+ user just wants a strong config picked for them without watching. If the user wants
25
+ to be **in the loop** — see the series, judge the alerts, turn the knobs, mark
26
+ incidents by eye — prefer the **`dtk-tune`** skill: it opens an interactive browser
27
+ cockpit that runs this **same engine** in its **Autotune** mode (server-side,
28
+ re-seeding the knobs) *and* lets them hand-tune and **Apply** in one place. The two
29
+ share the same search; pick by whether the user wants hands-on or hands-off.
30
+
23
31
  Work the steps in order. Do not invent SQL, incident times, or channel names —
24
32
  gather them. This skill is the procedure; for field detail read the matching
25
33
  file under `.claude/rules/detectkit/` (`autotune.md`, `detectors.md`,
@@ -79,8 +87,9 @@ generalize is rejected.
79
87
  Labels turn tuning from a good unsupervised default into a config optimised
80
88
  against *your* real incidents (it then optimises MCC and also tunes the alert
81
89
  window `consecutive_anomalies`). **The easiest, most reliable way to produce them
82
- is to mark incidents in `dtk tune` — offer this first**, before asking the user to
83
- recall timestamps:
90
+ is to mark incidents in `dtk tune` — offer this first**: open the cockpit and
91
+ **guide the user through marking incidents on the chart** (see the **`dtk-tune`**
92
+ skill for driving it), rather than asking them to recall timestamps:
84
93
 
85
94
  ```bash
86
95
  dtk tune --select <name>
@@ -73,8 +73,12 @@ Pick with the user (see `detectors.md` for the decision table):
73
73
  - **Unsure** → `mad` (robust default), `threshold: 3.0`.
74
74
 
75
75
  If you don't yet know the right detector or parameters, scaffold a robust starter
76
- (`mad`, `threshold: 3.0`) and let the **`dtk-autotune`** skill pick the detector
77
- and tune it on real data / labeled incidents after this metric loads.
76
+ (`mad`, `threshold: 3.0`) treat it as a **sandbox** the user will refine on the
77
+ real series after this metric loads. Two complementary ways to refine it (Step 7):
78
+ the **`dtk-tune`** skill opens an interactive browser cockpit where they turn the
79
+ knobs by hand and watch the band recompute live (with autotune built in), or the
80
+ **`dtk-autotune`** skill searches for the best detector/params automatically. You
81
+ don't need the perfect detector now — a sound starter is enough to open the cockpit.
78
82
 
79
83
  Set `window_size` to fit the data cadence (non-seasonal 100–500 points; seasonal
80
84
  several full cycles) and `min_samples` ≈ 10–30% of it. For a metric with a
@@ -163,6 +167,17 @@ dtk run --select <name> --steps detect # confirm the detector runs
163
167
  dtk test-alert <name> # confirm channels work (if alerting)
164
168
  ```
165
169
 
166
- Report the created file path and the commands to run it for real. If the user
167
- wants the detector chosen or tuned automatically (rather than the starter
168
- config), hand off to the **`dtk-autotune`** skill now.
170
+ Report the created file path and the commands to run it for real. Then offer to
171
+ **refine the starter on the real series** the metric so far is a sandbox, and
172
+ this is where most of the value is. Pick the path with the user:
173
+
174
+ - **Hands-on / "let me see and turn the knobs"** → the **`dtk-tune`** skill: it
175
+ loads some history and opens an interactive browser cockpit where they adjust
176
+ the detector live and **Apply** the result back. Its **Autotune** mode runs the
177
+ automatic search *in place* too, so this one path covers both styles — prefer it
178
+ whenever the user wants to be in the loop.
179
+ - **Fully automatic / "just pick one for me"** → the **`dtk-autotune`** skill: a
180
+ cross-validated command-line search that writes an annotated tuned config
181
+ (optionally against incidents you label first).
182
+
183
+ If they're happy with the robust starter for now, they can just run it and tune later.
@@ -0,0 +1,184 @@
1
+ ---
2
+ name: dtk-tune
3
+ description: >-
4
+ Interactively tune a detectkit metric's detector in the browser cockpit: stand
5
+ up a sandbox config, open `dtk tune`, and guide the user to turn the detector's
6
+ knobs on their real series and watch the confidence band recompute live —
7
+ **with the autotune engine built in** (an Autotune mode that searches
8
+ server-side and re-seeds the knobs), plus Label/Review to mark or confirm
9
+ incidents — then write the chosen config back into the metric YAML. Use when
10
+ the user wants to tune a detector by hand / interactively / in the browser, see
11
+ and adjust the band or alerts live, set up a tuning sandbox to "turn the knobs"
12
+ themselves, reduce false alerts hands-on, or visually mark/confirm incidents.
13
+ This is the primary, hands-on entry point for dialing in a metric; it contains
14
+ autotune, so prefer it whenever the user wants to be in the loop.
15
+ ---
16
+
17
+ # Tune a detectkit metric interactively (the cockpit)
18
+
19
+ `dtk tune` opens a localhost **browser cockpit** over a metric's **real**
20
+ persisted series. The user turns the detector's knobs and the confidence band,
21
+ flagged anomalies and would-fire alerts **recompute live** — no DB round-trip,
22
+ nothing leaves the machine — then clicks **Apply** to write the chosen config
23
+ **back into the metric YAML in place** (safely: validated, with the previous
24
+ version archived first).
25
+
26
+ It is the **hands-on umbrella** for tuning. The cockpit has four modes and one of
27
+ them runs the **real `dtk autotune` engine server-side** and re-seeds every knob
28
+ with the winner — so the user can auto-search *and* hand-tune *and* label
29
+ incidents without leaving the page. **Prefer this skill whenever the user wants
30
+ to be in the loop** (see, judge, adjust). Use the **`dtk-autotune`** skill
31
+ instead only for a fully hands-off, command-line search (e.g. CI, "just pick one
32
+ for me, I won't look").
33
+
34
+ Your job is to **set up the sandbox, open it, and guide the user through it** —
35
+ they drive the chart; you prepare it, explain each control in plain language, and
36
+ handle the follow-up (`dtk run` / `dtk clean`). This skill is the procedure; for
37
+ field detail read the matching file under `.claude/rules/detectkit/` (`cli.md`
38
+ has the full `dtk tune` reference, plus `detectors.md`, `autotune.md`,
39
+ `alerting.md`).
40
+
41
+ ## Step 0 — A metric with loaded data (the sandbox)
42
+
43
+ The cockpit charts a metric's **already-loaded** `_dtk_datapoints`, so you need a
44
+ metric that exists and has some history loaded.
45
+
46
+ - **A project root** contains `detectkit_project.yml`. If `profiles.yml` is still
47
+ the `dtk init` placeholder, set up the DB first with **`dtk-setup-project`**.
48
+ - **No metric yet?** This is the "stand up a sandbox to turn the knobs" path: hand
49
+ off to **`dtk-new-metric`** to design the query + a robust **starter** detector
50
+ (e.g. `mad`, `threshold: 3.0`) — that starter is exactly the sandbox the user
51
+ will refine here. Keep query design in that skill; never fabricate SQL here.
52
+ - **Load some history** (the more, the better the picture):
53
+
54
+ ```bash
55
+ dtk run --select <name> --steps load # incremental
56
+ dtk run --select <name> --steps load --from 2026-01-01 # backfill more history
57
+ ```
58
+
59
+ If the chart later looks empty or too short, load more with `--from`.
60
+
61
+ ## Step 1 — Open the cockpit
62
+
63
+ ```bash
64
+ dtk tune --select <name>
65
+ ```
66
+
67
+ The selector must resolve to a **single** metric. This starts a `127.0.0.1`
68
+ server and opens the browser. Useful flags:
69
+
70
+ - **Remote / headless machine** — add `--no-open` and share the printed URL (the
71
+ server is localhost-only; the user opens it via a tunnel/port-forward).
72
+ - **Focus a window** — `--from <date>` / `--to <date>` bound what's loaded.
73
+ - **No write-back / share a snapshot** — `--no-serve` writes a static read-only
74
+ HTML preview instead: the sliders still recompute, but there is **no Apply**
75
+ (and **no Autotune** — that needs the live server); **Save incidents**
76
+ downloads the labels file instead of writing it.
77
+
78
+ Tell the user plainly: *"I've opened an interactive chart of your metric — turn
79
+ the knobs and watch the band; tell me what you see and I'll help you decide."*
80
+
81
+ ## Step 2 — Orient the user to the cockpit
82
+
83
+ One chart fills the screen (the **windshield**); the live quality metrics ride
84
+ **pinned over it**; every control lives in an **always-visible side rail** that is
85
+ **mode-aware** (it shows only the current mode's controls). A **mode switch** above
86
+ the chart picks the job. Navigate a dense series by **scrolling to zoom**,
87
+ **dragging to pan**, double-clicking to reset, and dragging the **navigator
88
+ strip** below the chart. The **Points shown** slider trims to the most-recent N
89
+ points so recompute (and the read) is faster — view-only, never written.
90
+
91
+ These controls stay visible in **every** mode (they shape the band and the
92
+ alerts): **Points shown**, the alert rule (**direction** + **consecutive
93
+ anomalies**), and the **y = 0** reference-line toggle.
94
+
95
+ ## Step 3 — The four modes (autotune is one of them)
96
+
97
+ Walk the user to the mode that fits what they want to do:
98
+
99
+ - **Tune** — *turn the knobs.* The band leads. Adjust **detector type** (MAD /
100
+ Z-Score / IQR, or **Manual** = fixed lower/upper bounds), **threshold**,
101
+ **window size**, **recency weighting + half-life**, **detrend**, **smoothing**,
102
+ and **seasonality groups**; the band + anomalies + would-fire alerts recompute
103
+ on every change. The window-size / half-life readouts show the equivalent
104
+ wall-clock span. This is the core "turn the knobs yourself" loop.
105
+
106
+ - **Autotune** — *let the engine search, then refine.* Click **Run autotune** and
107
+ the **same engine `dtk autotune` uses** (seasonality → detector → grid → window,
108
+ cross-validated) runs **server-side over the window currently shown** (the
109
+ **Points shown** trim — the exact series on screen, not the full history), using
110
+ any marked/confirmed incidents as ground truth. It then **re-seeds every knob**
111
+ with the winner and shows the score + decision log. It's **advisory** — it
112
+ computes and re-seeds only, persists nothing (no run record, no `__tuned_<id>`
113
+ file, no detections), so the session stays lock-free; the user reviews the band
114
+ and **Applies**. Each run also streams a structured `LABELS → … → RESULT` log to
115
+ the terminal you launched from. (This is why `dtk tune` is the umbrella: the user
116
+ gets autotune **and** hand-tuning in one place.)
117
+
118
+ - **Label** — *mark the real incidents* (ground truth that sharpens both the live
119
+ quality metrics and a supervised Autotune). **Drag a span** over each incident;
120
+ or **Lasso anomalies** (loop a cloud of anomaly dots into one span per run); or
121
+ **Threshold capture** (grab every span past a horizontal line). **Save
122
+ incidents** writes a versioned `incidents/<metric>/*.yml` — the same store
123
+ `dtk autotune` reads.
124
+
125
+ - **Review** — *confirm the fired alerts.* When a config already looks good, click
126
+ each alert marker to cycle its verdict un-reviewed → **valid** (green) → **false
127
+ alarm** (slate). **Confirming an alert valid marks it as a ground-truth
128
+ incident**, and **Confirm all unreviewed valid** does the lot — so a clean
129
+ metric is validated in a few clicks **without hand-drawing spans**.
130
+
131
+ **Suggesting a path.** If the user *can recognise* their incidents on the chart,
132
+ start in **Label** (or **Review** to confirm good alerts) to give the engine
133
+ ground truth, then **Autotune** for a strong config, then **Tune** by eye, then
134
+ **Apply**. If they just want a quick strong default, go straight to **Autotune**
135
+ (unsupervised) and refine. If they want full manual control, stay in **Tune**.
136
+
137
+ ## Step 4 — Read the live quality, then Apply
138
+
139
+ As they tune, the metrics bar shows **incident catch rate (recall)**,
140
+ **false-alert rate** ("≈1 in N false"), and **reviewed N/M** — recomputed against
141
+ the marked + confirmed incidents (only those inside the loaded window are scored).
142
+ An optional **false-alert budget** (`false_alert_budget`, a fraction in `(0, 1]`,
143
+ on the metric then project, default `0.5`) gently flags the chip when the
144
+ false-alert rate exceeds it (tuning-only; labeling stays optional).
145
+
146
+ When the user is happy, they click **Apply to metric**. detectkit then, in order:
147
+ **validates** the config (a bad/untunable config is rejected and **nothing is
148
+ written**), **archives** the current YAML verbatim under
149
+ `metrics/.history/<metric>/`, and **re-emits** the metric in place with the tuned
150
+ detector (and updates the first alerting block's `consecutive_anomalies` if it has
151
+ one). Applying ends the session; saving incidents does not.
152
+
153
+ ## Step 5 — Recompute under the new config
154
+
155
+ `dtk tune` takes **no pipeline lock** and the live preview is a faithful
156
+ *approximation* — the **next `dtk run` is the source of truth**. Because the
157
+ detector params changed, the detector's identity changed, so detections recompute
158
+ under the new id and the old rows are orphaned:
159
+
160
+ ```bash
161
+ dtk run --select <name> # load → detect → alert under the new config
162
+ dtk run --select <name> --report # optional: a self-contained HTML report to confirm behavior
163
+ dtk clean --select <name> --execute # prune the orphaned old detector rows
164
+ dtk test-alert <name> # if alerting is configured
165
+ ```
166
+
167
+ ## When to hand off instead
168
+
169
+ - **Fully automatic, no browser** (CI, "just pick one for me") → the
170
+ **`dtk-autotune`** skill (it runs the same engine from the command line and
171
+ writes an annotated `__tuned_<id>.yml` without touching the original).
172
+ - **No metric yet** → **`dtk-new-metric`** to scaffold the sandbox, then come back.
173
+ - **DB not connected** → **`dtk-setup-project`**.
174
+
175
+ ## Final checklist — verify before declaring done
176
+
177
+ - [ ] Metric exists, resolves to a **single** selector, and has loaded datapoints
178
+ (ran `--steps load`, backfilled with `--from` if the chart was thin).
179
+ - [ ] You opened `dtk tune` (with `--no-open` + shared URL on a remote machine)
180
+ and told the user it's an interactive chart they drive.
181
+ - [ ] You explained the relevant mode(s) — including that **Autotune is built in**
182
+ and runs over the window shown — and which controls stay visible everywhere.
183
+ - [ ] After **Apply**, you ran `dtk run` to recompute and `dtk clean --execute`
184
+ to prune the orphaned old detector rows (and `dtk test-alert` if alerting).
@@ -12,7 +12,7 @@ It writes three things into the target directory:
12
12
  - ``.claude/rules/detectkit/`` — the reference docs the assistant reads on
13
13
  demand (overview, cli, project, metrics, detectors, alerting, autotune).
14
14
  - ``.claude/skills/`` — user-facing skills (``dtk-setup-project``,
15
- ``dtk-new-metric``, ``dtk-autotune``, ``dtk-feedback``).
15
+ ``dtk-new-metric``, ``dtk-tune``, ``dtk-autotune``, ``dtk-feedback``).
16
16
 
17
17
  The source of truth for all of the above lives in ``detectkit/cli/assets/claude``
18
18
  and ships with the package, so re-running this command after upgrading detectkit
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.44.0
3
+ Version: 0.45.0
4
4
  Summary: Metric monitoring with automatic anomaly detection
5
5
  Author: detectkit team
6
6
  License: MIT
@@ -61,6 +61,7 @@ detectkit/cli/assets/claude/skills/dtk-autotune/SKILL.md
61
61
  detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md
62
62
  detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md
63
63
  detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md
64
+ detectkit/cli/assets/claude/skills/dtk-tune/SKILL.md
64
65
  detectkit/cli/commands/__init__.py
65
66
  detectkit/cli/commands/autotune.py
66
67
  detectkit/cli/commands/clean.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes