Audience: anyone consuming OikosBot — as a GitHub Action in a workflow, as the published container, or as the CLI in a pipeline. This page is about running it and reading what it says. For what the numbers mean and how far they can be trusted, start with EXPLAINME and DEBT; the short version is repeated in What to trust below.
Composite Action |
|
Container |
|
The CLI’s entrypoint is oikosbot, with four subcommands: report, check,
compare and estate (plus self-analyze for dogfooding).
Every input is optional; the defaults are what examples/oikosbot-ci.yml uses.
| Input | Default | Meaning | Maps to CLI |
|---|---|---|---|
|
|
|
subcommand |
|
|
Directory to analyse; in |
positional arg |
|
(empty) |
Base directory for |
positional arg |
|
|
|
|
|
|
Output file; empty means stdout. The written path is exposed as the action’s
|
|
|
(empty) |
Path to an |
|
|
(empty) |
Eco-score floor, 0–100. Empty means "take it from the config, else 50". |
|
|
(empty) |
File holding the PR description, for the trade-off documentation check in
|
|
|
|
In |
|
|
pinned digest |
The container image to run. Pinned by digest, never by tag — override it only to test a candidate build. |
(action-level) |
|
Note
|
|
report-
Analyse the directory and emit findings. With
format: sarifthe output is uploaded to GitHub code scanning by the caller’s workflow;jsonis the same results with the SARIF envelope removed;textprints a summary. check-
Analyse, then compare each finding’s eco score against the floor. Below-floor findings are listed, and the run fails (exit 1) when the config says enforcement is blocking — either
enforcement: blockingormode: regulator. With anadvisor/consultantconfig the run reports and exits 0, printing which config made it advisory. compare-
Analyse base and head, project both onto the five Pareto objectives, and classify the change:
| Verdict | Meaning |
|---|---|
|
Head is better on at least one objective and worse on none. |
|
Head is worse on at least one objective and better on none. |
|
Better on some, worse on others. Must be documented with a
|
|
No objective moved by more than ε (1e-6). |
compare --check fails on an undocumented Regression or TradeOff only
when every driving objective is backed by Measured or Calibrated input.
That gate exists because a heuristic number must never be able to block a
merge, and it is enforced by the code, not by convention.
What that means in practice:
-
A function whose detected pattern maps to a known operation category is priced from the calibration table (
crates/oikosbot-analysis/src/calibration.rs) and carriesConfidence::Calibratedfor the measured rows (HashLookup,Sort,Allocation,MathCompute) — so a regression driven by those findings can block. -
A function with no recognised pattern stays on the naive complexity-derived estimate and carries
Confidence::Estimated, which can never block. -
When
--checkis requested but the drivers are heuristic, the run exits 0 and prints a::warning::naming the verdict and the confidence level. A gate that quietly does nothing is indistinguishable from one that passed, which is the failure mode OikosBot exists to find.
The estate path (oikosbot estate) is the one place with genuinely Measured
input: wall_minutes comes straight from the GitHub API.
Every finding is one analysed function (or one synthetic policy/security record) with:
-
location — file, line/column, and the end position used for range annotations, plus the function name;
-
rule_id —
oikosbot/<pattern>(see the rule table below) oroikosbot/generalfor a function with no detected pattern; -
suggestion — the concrete fix, also printed into the SARIF message;
-
resources — energy (J), duration (ms), carbon (gCO2e), memory (bytes);
-
health — eco (0–100), econ (0–100), quality (0–100), and the composite
overall = 0.4·eco + 0.3·econ + 0.3·quality; -
confidence — the ladder below;
-
resource_range — when the estimate is calibrated, the min/typical/max band behind
resources.resourcesis the typical bound. Absent on the naive path, where no band was computed.
| Confidence | Meaning |
|---|---|
|
Read from an instrument (the GitHub API’s wall-clock minutes). The only level that needs no calibration. |
|
Priced from a measured operation profile. Earned per finding, per operation kind — never assigned to a whole file or run. |
|
Heuristic: a pattern we recognise but have not measured (host-dependent I/O and string work), or the naive complexity path. Advises; never blocks. |
|
No estimate at all (the generic fallback row). |
|
Important
|
Absolute figures are still small, static and unvalidated against profiling data. Treat the relative signal — which function is worse, which direction a diff moves — as the product, and the absolute joules as an order-of-magnitude hint. See DEBT for the current list of unearned claims. |
| Rule id | Default level | Fires when |
|---|---|---|
|
warning |
Loop nesting depth ≥ 3. |
|
warning |
A |
|
warning |
A |
|
note |
|
|
warning |
|
|
note |
An allocation with a numeric literal above 1,000,000. |
|
note |
Five or more |
|
warning |
Emitted by the threshold, policy and security-correlation paths rather than by pattern detection. |
format: sarif emits SARIF 2.1.0 with one run, driver name oikosbot, and the
rules above in tool.driver.rules. Per result:
-
ruleIdis the finding’srule_id;levelcomes from the eco score (errorbelow 30,warningbelow 60, elsenote). -
locations[0].physicalLocation.regioncarries start/end line and column, so GitHub can annotate the whole function. -
propertiescarries the machine-readable payload:eco_score,econ_score,quality_score,overall_health,energy_joules,carbon_gco2e,duration_ms,memory_bytes,confidence, optionalsuggestion, optionalpareto_status/pareto_score/pareto_dominated_by, and — for calibrated estimates —resource_rangewithmin/typical/maxper axis.
oikosbot/general records are per-function telemetry, not defects: they appear
in json/text output and are filtered out of the SARIF results, so
analysing a repository does not raise a code-scanning alert for every function
in it.
Place an .oikos.yml in the analysed directory (or pass --config). The keys
that take effect today:
mode: regulator # consultant | advisor (default) | regulator
thresholds:
eco_minimum:
carbon: 50 # the eco-score floor, 0-100 (energy: is the fallback)
enforcement: blocking # fail the run when below the floor
exclude: # globs, matched against paths relative to the root
- "**/target/**"
- "**/node_modules/**"
analysis:
languages: [rust, javascript, python]-
mode: regulator(orenforcement: blocking) is what makes a below-floor finding fail the run. Without either,checkreports and exits 0, naming the config that made it advisory. -
analysis.languagesis intersected with what the tree-sitter analyser can actually parse (rust,javascript,python). Naming only unsupported languages is warned about loudly and falls back to the default set, because analysing nothing would be a silent no-scan. -
Other keys in
config/oikos.yaml(eco_standard,eco_excellence,complexity, and the datastore block) are parsed and discarded by the current loader. They are documented for the target design and take no effect; the file says so inline.
Policy files under policies/ (*.ecl, Eclexia) are a separate mechanism —
see policies/README. They are evaluated by
oikosbot-eclexia when --policy-dir is passed.
BOT_MODE configures the AffineScript webhook receiver in
bot-integration-affine/ — it is read in src/Config.affine, lower-cased, and
anything unrecognised becomes advisor.
| Value | Behaviour (from src/Types.affine and src/Report.affine) |
|---|---|
|
Answers questions and offers alternatives. PR comments open with "Oikos consultant — analysis". |
|
Proactive suggestions on pull requests. Comments open with "Oikos advisor — suggestions". |
|
Enforces policy compliance. Comments open with "Oikos regulator — policy review". |
The CLI’s .oikos.yml mode: key is the same three values, but it only
decides enforcement (regulator ⇒ blocking); it does not change the report
wording. GET /health on the receiver reports the active mode, which is the
quickest way to confirm what a deployment thinks it is.
|
Note
|
The GitHub App receiver is a scaffold: the webhook handler and HMAC verification exist, the HTTP listener is gated on upstream AffineScript stdlib work, and comments are not yet posted from a live deployment. Until then, CI is the supported path. |
| Symptom | Cause and fix |
|---|---|
`unknown mode '<x>' (report |
check |
compare)` |
The action’s |
|
|
|
The directories contain no file with a supported extension, or everything
was excluded. Check |
|
A file was analysed directly (not via a directory) and its extension is not
|
Run reports but never fails |
Expected in |
|
The verdict is real but its drivers are heuristic ( |
Every function is an alert in code scanning |
It should not be: |
Eco scores look uniformly high |
The eco score is a log scale anchored at 1 J; calibrated estimates are microjoule-scale, so most units clamp at 100. The eco threshold therefore discriminates far less than the Pareto verdicts, which compare base against head. This is a known, tracked limitation, not a silently passing gate. |
-
Direction and ranking (which unit is worse, which way a diff moves) are the product. They are deterministic for a given input tree.
-
Absolute joules, grams and milliseconds are static estimates. The calibrated path is better anchored than the naive one, but neither has been validated against profiling data on real hardware.
-
Confidencetells you which of the two you are looking at, per finding. Read it before acting on a number.