mcpField
E
entropy-check

entropy-check

github.com/fellowship-devTesting & quality3192 installsUpdated 2w ago
Repository

About entropy-check

Entropy is a read-only skill for assessing documentation and related quality signals across repository domains. It grades applicable signals, reports findings, and can update QUALITY_SCORE.md; it detects issues rather than fixing them.

Key features

  1. 01Grades domain quality from mechanical signals
  2. 02Checks documentation coverage and staleness
  3. 03Considers flow, issue, test, and hookshot signals
  4. 04Supports PR-scoped and full-repository scans
  5. 05Updates QUALITY_SCORE.md with scan results

Use cases

  1. 01Check documentation after a pull request merges
  2. 02Run a scheduled repository-wide quality sweep
  3. 03Get a health snapshot before a refactor
  4. 04Identify domains with stale or missing documentation

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/fellowship-dev/dogfooded-skills --skill entropy-check

After installing, type/entropy-checkin Claude Code to confirm it loaded.

Bundled filesscripts/contents-writeback.shtests/contents-writeback.test.sh

Details

From the project README

Entropy

Sensor. Detect, grade, report. Never fix.

Install via npx:

npx skills add fellowship-dev/dogfooded-skills/skills/ops/entropy-check

When to Use

  • Event-driven (PR merge): Triggered after a PR merges. Scans affected domains for doc staleness.
  • Weekly cron (full sweep): Runs against each product repo, updates QUALITY_SCORE.md with fresh grades.
  • Manual: When you suspect docs have drifted or want a current health snapshot before a refactor.

What It Does

Entropy is a read-only sensor. It computes domain quality grades from mechanical signals:

SignalWhat it measuresWeight
Doc coverageDoes docs/code-structure.md cover this domain?Binary
Flow coverageFlowChad flow defined for critical paths?Binary (frontend repos only)
Staleness deltaDays since last code commit vs. last doc update>30d = stale
Open issuesIssues tagged to domain in GitHub>3 open = signal
Test coverageFrom coverage report if available<60% = signal
Hookshot coverageIs doc-coverage.json current vs docs?Staleness

Grade scale:

  • A — All applicable signals green
  • B — 1 applicable signal missing or yellow
  • C — 2 applicable signals missing
  • D — 3+ applicable signals missing
  • F — No docs at all for this domain

Inapplicable signals are excluded from the grade denominator. A repo with 4 applicable signals all passing = grade A.


Instructions

0. Identify Target Repo
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename $(git remote get-url origin) .git)
ORG=$(git remote get-url origin | sed 's/.*github.com[:/]\([^/]*\).*/\1/')
FULL_REPO="$ORG/$REPO_NAME"
TODAY=$(date +%Y-%m-%d)

Read QUALITY_SCORE.md if it exists — this is the baseline to update. Read ARCHITECTURE.md if it exists — extract domain list. If neither exists, infer domains from directory structure (top-level source directories, one domain each).

1. Determine Signal Applicability

Before grading, determine which signals apply to this repo. Record applicability for the report.

Frontend Detection (S2 FlowChad)
HAS_FRONTEND=false
if [ -f "$REPO_ROOT/package.json" ]; then
  grep -q '"next"\|"react"\|"vue"\|"angular"\|"svelte"' "$REPO_ROOT/package.json" && HAS_FRONTEND=true
fi
if [ -d "$REPO_ROOT/app" ] || [ -d "$REPO_ROOT/pages" ] || [ -d "$REPO_ROOT/src/components" ]; then
  HAS_FRONTEND=true
fi

If HAS_FRONTEND=false: S2 FlowChad is inapplicable — exclude from grade denominator.

Hookshot Detection (S6)
HOOKSHOT_EXISTS=false
git -C "$REPO_ROOT" log -1 --format="%ci" -- .claude/doc-coverage.json 2>/dev/null | grep -q . && HOOKSHOT_EXISTS=true
[ -f "$REPO_ROOT/.claude/doc-coverage.json" ] && HOOKSHOT_EXISTS=true

S6 is always applicable but the score message differs — see Signal 6 below.

2. Determine Scope

PR-triggered mode: Given a PR number, identify which files changed:

# Get changed files from PR
GH_TOKEN=$GH_TOKEN gh api repos/$FULL_REPO/pulls/{PR_NUMBER}/files \
  --jq '.[].filename'

Map each changed file to its domain using directory prefixes. Only grade domains with changes.

Full sweep mode: Grade all domains. Read domain list from ARCHITECTURE.md or infer.

3. Per-Domain Grading

For each domain in scope:

Signal 1: Doc Coverage
# Is this domain mentioned in docs/code-structure.md?
grep -i "{domain_name}" $REPO_ROOT/docs/code-structure.md 2>/dev/null && echo "COVERED" || echo "MISSING"

Score: ✅ covered / ❌ missing

Signal 2: FlowChad Coverage

Skip entirely if HAS_FRONTEND=false. Record as "N/A — no frontend detected" in applicability table.

# Only run if HAS_FRONTEND=true
if [ "$HAS_FRONTEND" = "true" ]; then
  ls $REPO_ROOT/.flowchad/flows/ 2>/dev/null | grep -i "{domain_slug}" && echo "COVERED" || echo "MISSING"
fi

Score (frontend only): ✅ has flow / ❌ no flow

Signal 3: Staleness Delta

Find the most recent code commit date for files in this domain:

# Last commit touching domain files
git -C $REPO_ROOT log -1 --format="%ci" -- "{domain_directory_glob}" 2>/dev/null

Find the last update date for the domain's doc section:

# Last commit touching docs/code-structure.md
git -C $REPO_ROOT log -1 --format="%ci" -- docs/code-structure.md 2>/dev/null

Delta = days between last code commit and last doc update. Score: ✅ delta ≤30 days / ⚠️ delta 31-60 days (yellow) / ❌ delta >60 days

Signal 4: Open Issues
# Open issues tagged to this domain (use domain name as label or search term)
GH_TOKEN=$GH_TOKEN gh issue list --repo $FULL_REPO \
  --state open --search "{domain_name}" \
  --json number,title | jq length 2>/dev/null || echo "0"

Score: ✅ 0-3 open / ⚠️ 4-6 open (yellow) / ❌ >6 open

Signal 5: Test Coverage
# Look for coverage reports
ls $REPO_ROOT/coverage/ $REPO_ROOT/.nyc_output/ $REPO_ROOT/tmp/coverage/ 2>/dev/null
cat $REPO_ROOT/coverage/index.html 2>/dev/null | grep -o '[0-9.]*%' | head -1
# Rails: simplecov
cat $REPO_ROOT/coverage/.last_run.json 2>/dev/null | jq '.result.covered_percent'

If no coverage report is available → skip this signal (treat as neutral, not ❌). Score: ✅ ≥80% / ⚠️ 60-79% / ❌ <60% (only when coverage data is available)

Signal 6: Hookshot Coverage Staleness
COVERAGE_DATE=$(git -C $REPO_ROOT log -1 --format="%ci" -- .claude/doc-coverage.json 2>/dev/null)
DOCS_DATE=$(git -C $REPO_ROOT log -1 --format="%ci" -- docs/code-structure.md 2>/dev/null)

Distinguish two cases:

  • Hookshot not configured — .claude/doc-coverage.json has never existed (no git history for it, file absent): Score: ❌ "Hookshot not configured — recommend setup"

  • Hookshot stale — file has existed (git history found) but docs were updated more recently: Score: ⚠️ "Hookshot stale (coverage {COVERAGE_DAY} < docs {DOCS_DAY})" — commit dates, not a day count

  • Hookshot current — coverage was updated after or same day as docs: Score: ✅ "Hookshot current"

Detection logic:

if [ -z "$COVERAGE_DATE" ] && [ ! -f "$REPO_ROOT/.claude/doc-coverage.json" ]; then
  # Never been set up
  S6_SCORE="❌"
  S6_NOTE="Hookshot not configured — recommend setup"
elif [ -n "$DOCS_DATE" ] && [ -n "$COVERAGE_DATE" ]; then
  # Both exist — compare dates
  DOCS_EPOCH=$(date -d "$DOCS_DATE" +%s 2>/dev/null || date -j -f "%Y-%m-%d %H:%M:%S %z" "$DOCS_DATE" +%s 2>/dev/null)
  COV_EPOCH=$(date -d "$COVERAGE_DATE" +%s 2>/dev/null || date -j -f "%Y-%m-%d %H:%M:%S %z" "$COVERAGE_DATE" +%s 2>/dev/null)
  STALE_DAYS=$(( (DOCS_EPOCH - COV_EPOCH) / 86400 ))
  if [ "$STALE_DAYS" -gt 0 ]; then
    S6_SCORE="⚠️"
    S6_NOTE="Hookshot stale (coverage ${COVERAGE_DATE%% *} < docs ${DOCS_DATE%% *})"
  else
    S6_SCORE="✅"
    S6_NOTE="Hookshot current"
  fi
else
  S6_SCORE="❌"
  S6_NOTE="Hookshot not configured — recommend setup"
fi
Compute Grade

Collect only applicable signals. Count failing signals (❌) among applicable signals only:

APPLICABLE_SIGNALS = all signals minus inapplicable ones
FAILING = count of ❌ in APPLICABLE_SIGNALS
YELLOW = count of ⚠️ in APPLICABLE_SIGNALS
SCORE = FAILING + (YELLOW * 0.5), rounded up
  • SCORE = 0 → A
  • SCORE = 1 → B
  • SCORE = 2 → C
  • SCORE ≥ 3 → D
  • No docs at all → F

Example: repo with no frontend (S2 skipped), 5 applicable signals all green → grade A, not B.

4. Update QUALITY_SCORE.md

Read the existing file. Update each graded domain's row. Add new domains if discovered. Preserve existing rows for domains not in scope (only update what was re-scanned).

## Domains

| Domain | Grade | Last audit | Notes |
|--------|-------|------------|-------|
| {domain} | {grade} | {TODAY} | {brief note on what's missing, or "All signals green"} |

Write the updated file, then append to the History section:

| {TODAY} | {trigger: PR #{N} / weekly sweep / manual} | {N} domains scanned, {N} regressions, {N} improvements |
4a. Commit the write-back directly to the integration branch — no branch, no PR

Owner decision (2026-10-07): the write-back is committed straight to the scanned repo's integration branch with [skip ci]; it never opens a branch or a PR. Sibling write-back PRs all edited QUALITY_SCORE.md, conflicted on every merge and looped the full review chain.

  • Branch: the repo's default branch, resolved at run time (develop for fellowship-dev/pylot, whose releases promote develop → main). Never hardcode it.
  • Mechanism: the GitHub Contents API through scripts/contents-writeback.sh, not git push. Pylot workers' git-push-guard.sh denies pushes to main/master/develop (a path-scoped allow is fellowship-dev/pylot#3555, not shipped); do not retry a rejected push or look for another workaround.
  • Scope: QUALITY_SCORE.md only. The helper refuses any other path and any message without [skip ci] (exit 2) — fail the run loudly; never write another file this way.
  1. Nothing changed → report only. If no grade changed, no domain was added and no new Tooling drift was found, the only edit would be a History row. Discard it, commit nothing, post the step 8/9 report and finish.
  2. Otherwise commit. Fetch the branch's current file, apply this run's edits to it, put it:
WB="${PYLOT_WORKSPACE:-$HOME/.claude}/skills/entropy-check/scripts/contents-writeback.sh"
BASE=$(GH_TOKEN=$GH_TOKEN gh repo view "$FULL_REPO" --json defaultBranchRef --jq .defaultBranchRef.name)
MSG="chore: entropy scan — PR #{N} {title} [skip ci]"   # weekly/manual: chore: entropy scan — weekly sweep $TODAY [skip ci]
FRESH=$(mktemp)
SHA=$(GH_TOKEN=$GH_TOKEN bash "$WB" fetch "$FULL_REPO" "$BASE" "$FRESH")

Re-apply this run's row updates, new domains, Tooling section and History row to $FRESH (the branch's current content), keeping every other line exactly as it is there. Then:

GH_TOKEN=$GH_TOKEN bash "$WB" put "$FULL_REPO" "$BASE" QUALITY_SCORE.md "$FRESH" "$SHA" "$MSG"; echo "rc=$?"

rc=0 prints the commit sha. rc=3 means the sha went stale (HTTP 409/422 — another write-back landed first): fetch again and re-apply, at most 3 attempts in total. Any other code, or a third rc=3, fails the run loudly.

  • Always edit the freshly fetched content; never upload a stale local copy over it.
  • The commit message keeps the literal [skip ci] tag so the commit triggers no CI or deploy.
  • A direct commit opens no PR, so it cannot re-trigger the post-merge entropy rule.
  • The run is done once the commit lands; record its commit URL for step 8.
5. Signal Applicability Section

Include a "Signal Applicability" table in every report output:

## Signal Applicability

| Signal | Applicable? | Reason |
|--------|------------|--------|
| S1 Doc Coverage | Yes | — |
| S2 FlowChad | No | No frontend framework detected (bash/python scripts only) |
| S3 Staleness | Yes | — |
| S4 Open Issues | Yes | — |
| S5 Tests | Yes | No test framework found — recommend adding bats for shell scripts |
| S6 Hookshot | Yes | — |

Populate the Reason column with specifics:

  • S2 not applicable: "No frontend framework detected" + what was found (e.g., "bash/python scripts only", "Go/Rails repo")
  • S2 applicable: list detected framework (e.g., "Next.js detected in package.json")
  • S5 no data: "No coverage report found — signal skipped"
  • S5 data found: leave Reason blank or note the coverage percentage
  • S6: always applicable; Reason shows the hookshot status detail
6. Staleness Report

For any domain graded C, D, or F — or where grade regressed from previous — output a finding:

## Entropy Findings — {TODAY}

### Regressions (grade dropped)
- {Domain}: {old grade} → {new grade}
  Missing: {list of failing signals}
  Last doc update: {date}
  Last code commit: {date}

### Stable issues (same low grade)
- {Domain}: {grade} (unchanged since {date})
  Missing: {list}

### Improvements (grade improved)
- {Domain}: {old grade} → {new grade}

### Clean (A or B)
- {Domain}: {grade}
7. Imported Lib Drift (Architecture Check)

This check moved here from maintenance. It is an architecture signal, not an infra check.

Retired: the imported-command drift check covered a workflow that is no longer used. Skip this step; there is no ## Tooling drift to report.

8. PR-Triggered Output

When triggered by a PR merge event, output a comment-ready summary and post it on the merged PR once step 4a is done (write-back committed, or report-only):

## Entropy Scan — PR #{N} merged

Domains affected: {list}
Write-back: {commit URL on the default branch, or "none — no QUALITY_SCORE.md change"}

| Domain | Grade | Change | Notes |
|--------|-------|--------|-------|
| {domain} | {grade} | {→ or unchanged or ↑ or ↓} | {note} |

{If any regressions:}
⚠️ Doc staleness detected in: {domain list}
Recommended: update docs/code-structure.md for these domains before the next PR in this area.

Include the Signal Applicability table (see step 5) at the end of the comment.

9. Full Sweep Output (weekly cron)
## Entropy Weekly Sweep — {DATE}

{N} domains across {REPO_NAME}

### Grades
{Full grade table}

### Signal Applicability
{Signal applicability table}

### Action Items
{Domains graded D or F → recorded via file-finding.sh (existing issue or weekly digest)}

For D/F domains, record the finding through the shared filing helper (pylot-cli → scripts/file-finding.sh). Stale docs are non-blocking, so the helper comments on an open issue for the same domain or appends to the weekly digest issue — it never opens a new one:

FF="${PYLOT_WORKSPACE:-$HOME/.claude}/skills/pylot-cli/scripts/file-finding.sh"
GH_TOKEN=$GH_TOKEN bash "$FF" --repo "$FULL_REPO" \
  --title "Entropy: {domain} docs critically stale (grade {grade})" \
  --search "\"{domain} docs critically stale\"" \
  --body "Domain **{domain}** scored **{grade}** in the weekly entropy scan.

**Missing signals:**
{list}

**Last code commit to this domain:** {date}
**Last doc update:** {date}

Fix: update \`docs/code-structure.md\` and run \`/hookshot\` to regenerate hooks."

Comments

Markdown supported