Render the state of the ODD loop from the repository's committed .odd/ history and git alone - per-service loop state, findings ledger, trends, open telemetry gaps, next recommended action - read-only, no backend queries, no report written. Use when answering where the loop is, when /odd-status runs, or when a status must be computed offline from the clone.
Scanned 9/4/2026
Install to Claude Code
npx -y skills add using-system/oddyssey --skill get-status --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Get Status?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/using-system-get-status-oddyssey)More formats (shields.io, HTML) on the badges page.
---
name: get-status
description: Render the state of the ODD loop from the repository's committed .odd/ history and git alone - per-service loop state, findings ledger, trends, open telemetry gaps, next recommended action - read-only, no backend queries, no report written. Use when answering where the loop is, when /odd-status runs, or when a status must be computed offline from the clone.
---
# Get the ODD Loop Status
Answer "where is the loop?" for this repository, from its committed
memory alone. Every input is already in the clone — the stored reports,
the decisions ledger, and git — so the status costs no backend query, no
running stack, and no network: it is what the loop wrote down about
itself.
## Sources — and nothing else
- `.odd/observe-run-reports/` and `.odd/otel-instrumentation-reports/`:
frontmatters first, bodies only where a step below needs their
structured tables or a verification's rulings;
- git metadata about the repository and those files: report commit
dates, and each report's `revision` and `tree_anchor` fields against
the commits that came after it;
- `.odd/decisions.md`, the findings decision ledger — read through the
ledger contract `odd-memory`'s `decisions` reference owns: that
reference is the format's authority, this skill only reads what was
written under it. A
missing file means no decision has been recorded yet, which is a
fact, not an error.
All three are read under the memory contract (`odd-memory`): frontmatter
first, then sections, never a whole file without a stated need.
The caller may restrict the status to service name(s), a stack (`local`,
`grafana`, ...) and/or a deployment environment (`prod`, `uat`, ...).
When no filter is named, every stored report qualifies — no arguments is
the whole picture, not an empty scope.
Never query a backend, never start the stack, never write or edit a
report, a ledger, or any other file — this skill reads the loop, it does
not advance it. The one write in the status surface is the decision
`odd-memory`'s `decisions` reference records. The status renders in
the conversation,
as tables — never a committed artifact.
## Render first, then judge
The build order below is applied by the script bundled with this
skill, in **one shell call** before any reasoning starts — and one
more, with classification flags, when the first run defers tree
entries you can classify:
```bash
python3 <this skill's directory>/scripts/odd_status.py --render \
[--service <name>]... [--stack <stack>] [--env <environment>]
```
Pass the caller's scope as flags — the service name(s) exactly as
named, the stack, the environment; nothing when the caller named
nothing. The script prints the status as markdown: the inventory (or
step 1's stop, or the filter-matches-nothing statement), the loop
state with one row per lineage (a service set on a stack and an
environment, or a plan on a stack), the findings ledger with its
burn-down, the trends over the pairs comparable by construction (a
report and the one that `verifies` it), the open telemetry gaps as
last recorded, the next recommended action — every row citing its
inputs — and a closing **Judgment needed** list of everything the rules
deferred: a ruling whose wording states no state or two, verifications
that disagree, a verification stating no verdict, a quick verification
that ruled only part of its items, a boundary the files cannot settle
(tree entries the anchor cannot classify, an entry present on one side
only, a commit-date boundary with commits since), a ruling on an id its
chain does not define (the same finding, or a homonym), a quick
report's gaps section opening with its not-queried list, a section not
lifted or cut by a cap, an unreadable report, a malformed frontmatter
value, a skipped ledger row. The action column uses step 6's three
actions plus `fix pending` (observed, nothing landed, nothing to
verify), `plan verified` / `plan awaits verification` for a plan's
lineage, and `judgment needed` for a deferral.
When you know which top-level entries can or cannot change the
observed service's runtime in this repository, re-run with
`--runtime <entry>` or `--non-runtime <entry>` so the rule decides
instead of deferring — the flags hold for the whole repository, so
when an entry is runtime for one lineage only, leave the deferral and
say so. `--today YYYY-MM-DD` sets the date the cadence rule counts
from; `--help` lists the rest.
**Print the rendering in the conversation as the status, unchanged** —
the last one you ran, and say which flags it ran with. The tables are
the rules; never rewrite a rendered row: when the sources contradict
one, flag the row in the paragraph below, with the evidence. Then rule
on the Judgment needed items — those and nothing else — in one short
paragraph after the rendering, from the fact sheet (`odd_status.py`
without `--render` prints it as JSON; per report, `tree_anchor_diff`,
`commits_since`, `benchmarks`, `findings` and `sections` are the keys
a judgment reads) and from a report body only when an item names
one. State each judgment as what it changes in the
tables above ("F1 of <report> reads as fixed: 'still passing' is a pass
row"; "the `.apm` entry is the package's prompts, non-runtime: the loop
can rest"), and nothing when an item changes nothing; the list itself
stays as printed. Runs listed apart in the trends are information, not
a deferral: compare them only when the caller asks.
When `python3` is missing, the script is not next to this file (an
install that dropped `scripts/`), or it exits non-zero, say so in one
line and build the status by hand, exactly as the steps below describe
— the script is the same rules applied by code, never a different
status.
## Build the status in this order
1. **Inventory — frontmatters only.** List both directories and read
every frontmatter, no bodies yet; the memory invariant (below) is
checked here, over every stored report, and rendered right after
the inventory. No `.odd/` directory or no reports
at all: say the loop has not started here, point at
`/odd-instrument-otel` or `/odd-observe`, and stop — that IS the
status, not a failure.
2. **Per-service loop state.** One row per service (`services` for
observation reports; an instrumentation report contributes to the
services its plan covers, `project` names its scope): last
observation (date, `stack`, `environment`, mode, `depth` — `full`
when the frontmatter has none — `workload` when present), last
verification (`mode: verify` reports — their `verifies` value names
what they replayed) with its verdict from the report body — a
`depth: quick` verification renders its coverage
(`PASS (quick, 3 of 5 ruled)`) and satisfies "verified" only for
the items it ruled, never for the service as a whole; a
verification's presence rulings satisfy "verified" only for the
items ruled `closed`, `present, unattributed` closes nothing — and
the chain as the files tell it:
observed -> fixed -> verified. A `mode: re-measure` report is an
observation event, never a verification: it replayed the protocol of
the report its `verifies` names without ruling on a fix — count it as
the last observation when newest, and never let it satisfy "verified"
in the chain.
"Fixed" means commits landed after the report's `revision`,
**excluding commits that only touch the loop's own memory or
documentation** — the memory being the append-only report stores
and the ledger (`.odd/observe-run-reports/`,
`.odd/otel-instrumentation-reports/`, `.odd/decisions.md`), never
`.odd/benchmarks/`: a benchmark is living source, and a commit
changing one is a fix like any other. Scope the commit test to the
service's path when a report names one (an instrumentation report's
`project`); otherwise say the count is repo-wide, not service-scoped.
A verification covers the commits its own `revision` has as ancestors
— but in a squash-merge workflow that `revision` never becomes an
ancestor of the merged history, so ancestry alone cannot prove
coverage: a commit whose squash introduced the verification report
itself is covered by that verification, and when ancestry is
otherwise inconclusive, say coverage is uncertain rather than ruling
a verification due. When a report carries a `tree_anchor`, that is
the **preferred boundary**: compare its entry hashes against
`git ls-tree` of the candidate commit, ignoring `.odd` (its
top-level hash moves with every report written) and every entry
that cannot change the observed service's runtime behavior —
documentation is the canonical case, but so are CI configuration,
generated/packaging artifacts, and release-metadata files — then
test the benchmark by path: the one the report's scenario record
names (`.odd/benchmarks/<name>/`) — nothing when it names none, a
benchmark the run did not use cannot be its fix; commits touching
that path since the report (`git log <revision>..HEAD -- <path>`
when `git rev-parse --verify <revision>^{commit}` succeeds,
otherwise `git log --since=<the report file's own commit date> --
<path>`, the report's own commit ignored). Equal hashes and no
benchmark
commit mean no code change, and the comparison resolves in any
clone whatever the merge strategy; when the only differing entries
are ones you cannot classify, the boundary is uncertain — say so,
never rule "code changed". When a report carries neither an anchor
nor a `revision`, its commit date — already a source — is the
substitute boundary.
Pre-convention reports (no `verifies` field) leave the chain
"unknown (pre-convention)" — state it, never reconstruct it from
prose.
3. **Findings ledger.** From each report's ranked findings table, each
verification's rulings, and the decisions ledger: open,
fixed-and-verified, regressed, or declined, with severity — the
burn-down of the loop's backlog. A finding no verification ever ruled
on stays open, whatever a commit message claims — `not ruled (quick)`
in a quick verification is not a ruling — unless the
decisions ledger declines it.
Cross-reference every finding against `.odd/decisions.md` on the key
that ledger uses: `<exact report filename> / <finding ID as the
report's ranked-findings table names it>` — the exact filename is
what disambiguates finding IDs, which are report-local (two reports
can both have an "F4"). Rows are appended, never rewritten, so **the
latest row for a finding wins**: when it carries a declining verdict
(`wontfix`, or any verdict other than `open`) the finding renders
**declined** — its verdict, decision date, and rationale in place of
the open state — and when it carries `open` the finding is reopened,
back to whatever the reports rule. A finding with no ledger row
renders exactly as it would without the ledger.
Count open, fixed-and-verified, regressed, and declined **separately**
in the burn-down: a declined finding was decided, not fixed, and
merging the two would hide the backlog's real shape.
4. **Trends.** For operations appearing in the per-operation summary
table of two or more reports of the same service, stack, environment
and `workload`: p50/p95/p99 and error rate across runs — improved /
regressed / stable, with the stored numbers. Depth does not break
comparability: section 2's numbers come from the same source at
both depths, so a quick and a full run of the same scenario compare
on the operations both carry. Comparability is
stricter than the frontmatter: reports whose `workload` differs are
incomparable, and for drive-mode reports (and verifications or
re-measures replaying one) so are runs whose recorded scenario or
process identity (`instance`, `process_restarted`) differ — a driven
session and a process-per-call run measure different things whatever
the frontmatter says. A verification or re-measure and the report its
`verifies` names replay the same scenario by construction and always
compare — unless the benchmark the drive replays moved between them,
which the verification's scenario record states: then only what the
record says still compares (the load unchanged) does, and the rest
is listed apart. List incomparable runs apart, never diff them.
Stored numbers only — no live queries.
5. **Open telemetry gaps.** Gaps recorded in report bodies and not
closed by a later verification ruling or instrumentation report —
`closed` is the only closing ruling; a planned item ruled
`present, unattributed` stays open. A
quick report's `not queried (quick): ...` list is a statement about
that mission, never a gap — do not count it; and a gap a quick
verification lists as `not ruled (quick)` stays open, not closed.
When gaps dominate a service's picture, the recommendation below
should say instrument, not observe.
6. **Next recommended action** — the maturity principle operationalized,
per service: a **verification is due** (service-relevant commits —
step 2's rule — landed after the last report's `revision` and no
verification covers them), a **new observation is due or overdue**
(the cadence of past observation dates has lapsed, or recent verdicts
keep churning), or the **loop can rest** (recent verification, stable
verdicts, no unverified change). Every recommendation cites its
inputs — dates, verdicts, revisions — evidence over impressions
applies to the meta-loop too.
## The memory invariant
"Model-visible means logged": everything a later mission consumes is
in `.odd/`, in the shape the `odd-memory` contract fixes — and the
script checks it after the fact, over **every** stored report and
decision, filtered status or not. Per report: the filename convention,
the frontmatter fields the kind requires (`services`, `stack`,
`environment`, `mode`, `depth`, `window` as `start/end` UTC,
`run_name` and `date` matching the filename; `project` for a plan),
and a `verifies` that names a stored file when the mode is a replay.
Per decision row: a report that exists and a finding it carries (the
ledger's own skipped rows). The fact sheet carries the result under
`invariant`, and the rendered status carries a `## Memory invariant`
section: the counts, then one line per violation.
A violation is **never a failure**: the store is append-only, so a
report is never edited to repair it — a new run supersedes it — and a
decision row is appended, never rewritten. The status is where a
reader learns that a decision points at nothing; the remedy is the
next run, or a new row. A report whose only gap is a field it
predates (`depth`, read as `full` the way the loop state already
renders it) is not a violation: the fact sheet lists it under
`legacy`, and the section names it in a note next to the counts,
since nothing can ever change it.
## A filter that matches nothing is still a status
When the caller restricted the status — service, stack, environment —
and no stored report matches, say exactly two things and stop:
- **what was searched**: each filter and its value, kept distinct (a
stack scope is not an environment scope);
- **what exists instead**: the distinct services, stacks, and
environments present across the stored frontmatters — the inventory
of step 1, which is already read.
Example: "no report with environment `prod` — all 4 stored reports are
`environment: local`." That IS the status, not a failure: it names the
miss and hands back the values that let the caller correct the scope in
one turn.
Service names match **exactly** against the frontmatter `services`
values (and an instrumentation report's plan scope): a partial name
misses, and falls into the statement above rather than being guessed
into a match. Never render the unfiltered picture under a scope that
matched nothing, never render an empty table silently, and never error.
## Degrade gracefully
Degrade gracefully everywhere: a single report, reports predating newer
frontmatter fields, a body missing a structured section — render what
exists, mark what cannot be known ("no verification yet", "chain
unknown"), and never fail the whole status over one unreadable report.
The ledger degrades the same way: a malformed row, or one naming a
report or finding ID that does not exist, is **reported and skipped** —
say which row and why, then render the rest of the status. A broken
ledger row is never fatal, and never silently dropped either.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!