Summary
Renew CodeKeeper around a metric-native MetricReport interface designed for recurring human and AI-assisted code quality review.
This issue tracks the design direction and implementation progress toward the 1.0 interface.
Background
CodeKeeper originally came from an engineering management need: observing the relationship between codebase health, team behavior, and business context over time.
When direct code ownership is difficult, continuous metric observation can help reveal how teams are working with the codebase and where quality risks may be accumulating.
That motivation still matters, but the practical workflow has changed. In the current development environment, it is more useful for CodeKeeper to produce structured metric reports that humans and AI agents can review periodically.
The renewed direction is therefore not to optimize first for long-term time-series analysis, but to make each report useful as input for recurring AI-assisted code quality review.
Motivation
CodeKeeper’s core value is keeping code metric values visible over time, independent of whether metric offenses are enforced strictly in day-to-day development.
The renewed interface should make those metric values easy to review periodically. A typical workflow is:
- Run CodeKeeper periodically or before quality review work.
- Generate a JSON metric report.
- Ask a human or AI agent to identify hotspots, risks, and focused refactoring candidates.
- Use metrics as review signals, not as hard pass/fail thresholds.
Why CodeKeeper in addition to RuboCop?
RuboCop is still important. It gives fast feedback, keeps code style consistent, and helps developers avoid many common problems during daily development.
A natural question is whether RuboCop Metrics cops can be reused as a metric collection interface. RuboCop can serialize offense results and summaries as JSON, but that output is structurally an offense report, not a metric inventory.
There are two important differences.
First, RuboCop Metrics output is threshold-gated. It reports offenses when values exceed configured limits such as Max. Values that stay under the threshold are not emitted as metric facts. For periodic code quality review, CodeKeeper needs the opposite default: collect metric values first, then let humans or agents decide which values deserve attention.
Second, RuboCop output is policy-filtered. Inline disable comments, Exclude, disabled cops, allowed method settings, and relaxed thresholds can suppress or hide values. This remains true even if RuboCop is configured aggressively to surface more metric offenses.
CodeKeeper’s role is to keep metric facts visible independently of offense thresholds and suppression policy. It complements RuboCop by producing structured metric reports that humans and AI agents can use for periodic quality review.
Design Decisions
- The central output object is
MetricReport.
measurements are the source of truth.
summary is derived from measurements.
summary.metrics.*.top_hotspots contains up to five measurements ordered by descending value, with deterministic ties by path, start line, and scope name.
- Metrics are measured at their natural scope.
- Scope names identify the owner: nested scopes carry their full namespace, and
class << self with its methods resolves to the enclosing constant (class << Foo, Foo.bar) only where self statically is that constant, that is directly in a class or module body. Under method bodies and blocks the receiver stays self.
- File paths are location metadata, not the primary grouping model.
- File-level, directory-level, domain-level, or owner-level summaries can be derived downstream.
- JSON is the only output format. Tabular views such as CSV can be derived from
measurements downstream.
- RuboCop is used as the metric calculation foundation where practical.
- RuboCop offense policy configuration is intentionally not applied.
- Time-series storage is not the primary interface, but can be built from repeated reports.
Metric Scopes
abc_metric: method-like scopes
cyclomatic_complexity: method-like scopes
class_length: class/module-like scopes
Proposed JSON Interface
{
"summary": {
"metrics": {
"abc_metric": {
"count": 10,
"max": 18.2,
"top_hotspots": []
}
}
},
"measurements": []
}
Example measurement:
{
"metric": "abc_metric",
"scope_type": "method",
"scope_name": "User#save!",
"path": "app/models/user.rb",
"start_line": 42,
"end_line": 80,
"value": 18.2
}
Implementation Plan
Non-goals
- Do not mirror
.rubocop.yml policy configuration.
- Do not make file-level summary the primary data model.
- Do not make time-series storage the primary interface.
- Do not preserve legacy engine behavior in the 1.0 interface.
- Do not provide a CSV output format in the 1.0 interface.
Progress
Done
Remaining
Acceptance Criteria
- The public output model uses
MetricReport.
- JSON output contains
summary and measurements.
- JSON is the only supported output format.
- Measurements include metric name, scope type, scope name, path, line range, and value.
- Summary data is derived from measurements.
top_hotspots returns a bounded, deterministic top-five list for each metric.
- RuboCop-compatible metric calculation behavior is used where available.
- RuboCop policy configuration does not suppress or alter measurements.
- README explains the AI-assisted review workflow.
- Legacy metric engine and legacy output aliases are removed before 1.0.
- Runtime dependencies are reviewed and unnecessary direct dependencies are removed.
Summary
Renew CodeKeeper around a metric-native
MetricReportinterface designed for recurring human and AI-assisted code quality review.This issue tracks the design direction and implementation progress toward the 1.0 interface.
Background
CodeKeeper originally came from an engineering management need: observing the relationship between codebase health, team behavior, and business context over time.
When direct code ownership is difficult, continuous metric observation can help reveal how teams are working with the codebase and where quality risks may be accumulating.
That motivation still matters, but the practical workflow has changed. In the current development environment, it is more useful for CodeKeeper to produce structured metric reports that humans and AI agents can review periodically.
The renewed direction is therefore not to optimize first for long-term time-series analysis, but to make each report useful as input for recurring AI-assisted code quality review.
Motivation
CodeKeeper’s core value is keeping code metric values visible over time, independent of whether metric offenses are enforced strictly in day-to-day development.
The renewed interface should make those metric values easy to review periodically. A typical workflow is:
Why CodeKeeper in addition to RuboCop?
RuboCop is still important. It gives fast feedback, keeps code style consistent, and helps developers avoid many common problems during daily development.
A natural question is whether RuboCop Metrics cops can be reused as a metric collection interface. RuboCop can serialize offense results and summaries as JSON, but that output is structurally an offense report, not a metric inventory.
There are two important differences.
First, RuboCop Metrics output is threshold-gated. It reports offenses when values exceed configured limits such as
Max. Values that stay under the threshold are not emitted as metric facts. For periodic code quality review, CodeKeeper needs the opposite default: collect metric values first, then let humans or agents decide which values deserve attention.Second, RuboCop output is policy-filtered. Inline disable comments,
Exclude, disabled cops, allowed method settings, and relaxed thresholds can suppress or hide values. This remains true even if RuboCop is configured aggressively to surface more metric offenses.CodeKeeper’s role is to keep metric facts visible independently of offense thresholds and suppression policy. It complements RuboCop by producing structured metric reports that humans and AI agents can use for periodic quality review.
Design Decisions
MetricReport.measurementsare the source of truth.summaryis derived from measurements.summary.metrics.*.top_hotspotscontains up to five measurements ordered by descending value, with deterministic ties by path, start line, and scope name.class << selfwith its methods resolves to the enclosing constant (class << Foo,Foo.bar) only whereselfstatically is that constant, that is directly in a class or module body. Under method bodies and blocks the receiver staysself.measurementsdownstream.Metric Scopes
abc_metric: method-like scopescyclomatic_complexity: method-like scopesclass_length: class/module-like scopesProposed JSON Interface
{ "summary": { "metrics": { "abc_metric": { "count": 10, "max": 18.2, "top_hotspots": [] } } }, "measurements": [] }Example measurement:
{ "metric": "abc_metric", "scope_type": "method", "scope_name": "User#save!", "path": "app/models/user.rb", "start_line": 42, "end_line": 80, "value": 18.2 }Implementation Plan
Measurementobjects.MetricReportas the central output object.summaryas derived data from measurements.Non-goals
.rubocop.ymlpolicy configuration.Progress
Done
MetricReportinterface in this issue.MeasurementandMetricReportas the public output model.Remaining
config.format.Acceptance Criteria
MetricReport.summaryandmeasurements.top_hotspotsreturns a bounded, deterministic top-five list for each metric.