Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/release-goal-audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,22 @@ jobs:
- name: Install, build, test
working-directory: tools/goal-audit
run: |
# Build monorepo sibling first
(cd ../readiness-core && npm ci && npm run build)
npm ci
npm run build
npm test

- name: Publish to npm
working-directory: tools/goal-audit
run: npm publish --access public --provenance
run: |
# Rewrite to registry version for publish
node -e "
const fs = require('fs');
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
p.dependencies['@cobusgreyling/readiness-core'] = '^1.0.0';
fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n');
"
npm publish --access public --provenance
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
12 changes: 11 additions & 1 deletion .github/workflows/release-loop-audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,22 @@ jobs:
- name: Install, build, test
working-directory: tools/loop-audit
run: |
# Build monorepo sibling first
(cd ../readiness-core && npm ci && npm run build)
npm ci
npm run build
npm test

- name: Publish to npm
working-directory: tools/loop-audit
run: npm publish --access public --provenance
run: |
# Rewrite to registry version for publish
node -e "
const fs = require('fs');
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
p.dependencies['@cobusgreyling/readiness-core'] = '^1.0.0';
fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n');
"
npm publish --access public --provenance
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
49 changes: 49 additions & 0 deletions .github/workflows/release-readiness-core.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Release readiness-core

on:
push:
tags:
- 'readiness-core-v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to publish (e.g. readiness-core-v1.0.0)'
required: true
type: string

permissions:
contents: read
id-token: write

jobs:
test-and-publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', github.event.inputs.tag) || github.ref }}

- uses: actions/setup-node@v7
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
cache: 'npm'
cache-dependency-path: tools/readiness-core/package-lock.json

- name: Ensure npm supports trusted publishing (OIDC)
run: |
npm install -g npm@latest
npm install -g sigstore

- name: Install, build, test
working-directory: tools/readiness-core
run: |
npm ci
npm run build
npm test

- name: Publish to npm
working-directory: tools/readiness-core
run: npm publish --access public --provenance
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
39 changes: 29 additions & 10 deletions STATE.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
# Loop State — loop-engineering reference

Last run: 2026-07-21T08:49:11Z (automated daily-triage workflow)
Last run: 2026-07-21T14:11:50Z (PR triage / scheduled maintenance)

## High Priority (loop is acting or waiting on human)

- Maintain loop readiness score ≥ 58 (current: **100**, level **L3**).
- Keep npm packages current after tool changes (tag `loop-audit-v*`, `loop-init-v*`, `loop-cost-v*` — see docs/RELEASE.md).

- Maintain loop readiness score ≥ 58 (current: **100**, level **L3**). Harness-runtime warn: no `.foundry/stack.yaml` — optional dogfood `loop-init --with-foundry` (human).
- **Shipped (recent):** [#324](https://github.com/cobusgreyling/loop-engineering/pull/324) Foundry funnel + [v1.6.0](https://github.com/cobusgreyling/loop-engineering/releases/tag/v1.6.0); ecosystem/docs/star-history automation; **triage 2026-07-21:**
- Merged [#335](https://github.com/cobusgreyling/loop-engineering/pull/335) loop-context circuit breaker wiring (@Tusm11)
- Merged [#318](https://github.com/cobusgreyling/loop-engineering/pull/318) live telemetry on docs site (@THRISHAL12345)
- Merged [#316](https://github.com/cobusgreyling/loop-engineering/pull/316) loop-sync requiredFiles (+ dropped accidental `pr-description.md`)
- Closed [#315](https://github.com/cobusgreyling/loop-engineering/pull/315) superseded housekeeping draft
- **Waiting on author (changes requested):**
- [#317](https://github.com/cobusgreyling/loop-engineering/pull/317) goal-init — strip `.test-manual/`, `scratch.js`, `PR_DESCRIPTION.md`, unrelated `dist/`
- [#321](https://github.com/cobusgreyling/loop-engineering/pull/321) readiness-core — rebase (conflicts), strip noise dist, add tests, clarify private vs publish
- Issues: [#332](https://github.com/cobusgreyling/loop-engineering/issues/332) release prep · [#320](https://github.com/cobusgreyling/loop-engineering/issues/320) weekly report

## Watch List

- Expand contributor failure stories (dependency sweeper, multi-loop).
- Collect a production story for Post-Merge Cleanup.
- Validate `loop-init` scaffolds on fresh projects across all patterns.
- Contributor failure stories; Post-Merge Cleanup production story
- Cursor/docs GFI: #220, #223, #224; #117–#120, #147, #173, #195, #196
- Validate `loop-init --with-foundry` on fresh projects
- Optional: StackMap #300, Pluribus #262, loop.js #246

## Housekeeping (2026-07-21 triage)

- Human PR triage completed (merge 316/318/335; close 315; CHANGES_REQUESTED 317/321).
- Main CI green; readiness 100/L3; npm current as of last release prep.

## Recent Noise

- Star-history / sparse automated STATE overwrite (expected).
- Automated daily-triage can clobber curated High Priority — re-curate after merge.

## Recent Noise (ignored this run)
## Post-Run Critique

- Friction: automated daily-triage still overwrites curated STATE.
- Adjustment: land curated maintenance after triage; consider workflow preserve-section later.

---
Run log: Updated by `.github/workflows/daily-triage.yml`. See `LOOP.md` for cadence and gates.
Run log: Updated by daily-triage.yml and scheduled maintenance. See LOOP.md.
10 changes: 8 additions & 2 deletions docs/RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Release playbook — npm packages

This repo ships nine public npm packages from `tools/`:
This repo ships ten public npm packages from `tools/`:

| Package | Directory | Release tag |
|---------|-----------|-------------|
| `@cobusgreyling/readiness-core` | `tools/readiness-core` | `readiness-core-v*` |
| `@cobusgreyling/loop-audit` | `tools/loop-audit` | `loop-audit-v*` |
| `@cobusgreyling/loop-init` | `tools/loop-init` | `loop-init-v*` |
| `@cobusgreyling/loop-cost` | `tools/loop-cost` | `loop-cost-v*` |
Expand All @@ -20,6 +21,7 @@ Link npm to GitHub, then for **each package** on [npmjs.com](https://www.npmjs.c

| Package | Repository | Workflow filename |
|---------|--------------|-------------------|
| `@cobusgreyling/readiness-core` | `cobusgreyling/loop-engineering` | `release-readiness-core.yml` |
| `@cobusgreyling/loop-audit` | `cobusgreyling/loop-engineering` | `release-loop-audit.yml` |
| `@cobusgreyling/loop-init` | `cobusgreyling/loop-engineering` | `release-loop-init.yml` |
| `@cobusgreyling/loop-cost` | `cobusgreyling/loop-engineering` | `release-loop-cost.yml` |
Expand Down Expand Up @@ -47,6 +49,10 @@ Edit `version` in the package `package.json`, update that package's `CHANGELOG.m
Tag pushes trigger the release workflows:

```bash
# readiness-core (MUST be published before loop-audit and goal-audit)
git tag readiness-core-v1.0.0
git push origin readiness-core-v1.0.0

# loop-audit (runs tests before publish)
git tag loop-audit-v1.6.0
git push origin loop-audit-v1.6.0
Expand Down Expand Up @@ -84,7 +90,7 @@ git tag goal-audit-v1.0.2
git push origin goal-audit-v1.0.2
```

Workflows: `.github/workflows/release-loop-audit.yml`, `.github/workflows/release-loop-init.yml`, `.github/workflows/release-loop-cost.yml`, `.github/workflows/release-loop-sync.yml`, `.github/workflows/release-loop-context.yml`, `.github/workflows/release-loop-mcp-server.yml`, `.github/workflows/release-loop-worktree.yml`, `.github/workflows/release-loop-gate.yml`, `.github/workflows/release-goal-audit.yml`.
Workflows: `.github/workflows/release-readiness-core.yml`, `.github/workflows/release-loop-audit.yml`, `.github/workflows/release-loop-init.yml`, `.github/workflows/release-loop-cost.yml`, `.github/workflows/release-loop-sync.yml`, `.github/workflows/release-loop-context.yml`, `.github/workflows/release-loop-mcp-server.yml`, `.github/workflows/release-loop-worktree.yml`, `.github/workflows/release-loop-gate.yml`, `.github/workflows/release-goal-audit.yml`.

## Verify after publish

Expand Down
113 changes: 113 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
});
</script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>

Expand Down Expand Up @@ -616,6 +617,27 @@ <h2>Ready to stop prompting?</h2>
</div>
</div>

<section id="telemetry" class="wrap">
<p class="section-label">Dogfooding</p>
<h2 class="section-title">Live Telemetry</h2>
<p class="section-desc">Machine-readable data rendered directly from <a href="https://github.com/cobusgreyling/loop-engineering/blob/main/loop-run-log.md"><code>loop-run-log.md</code></a>. This repo runs loops.</p>

<div class="telemetry-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px; margin-top: 32px; margin-bottom: 40px;">
<div class="card" style="padding: 20px; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 8px;">
<h3 style="font-size: 1rem; margin-bottom: 16px; color: var(--text-muted);">Loop Readiness Score</h3>
<canvas id="scoreChart" height="200"></canvas>
</div>
<div class="card" style="padding: 20px; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 8px;">
<h3 style="font-size: 1rem; margin-bottom: 16px; color: var(--text-muted);">Cumulative Tokens (Estimate)</h3>
<canvas id="tokenChart" height="200"></canvas>
</div>
<div class="card" style="padding: 20px; background: var(--bg-card); border: 1px solid var(--border-subtle); border-radius: 8px;">
<h3 style="font-size: 1rem; margin-bottom: 16px; color: var(--text-muted);">Automated vs Escalated Runs</h3>
<canvas id="escalationChart" height="200"></canvas>
</div>
</div>
</section>

<section id="adopters" class="wrap">
<p class="section-label">Community</p>
<h2 class="section-title">Adopters</h2>
Expand Down Expand Up @@ -1023,11 +1045,102 @@ <h4>Your project here</h4>
});
}

async function renderTelemetry() {
try {
const res = await fetch('https://raw.githubusercontent.com/cobusgreyling/loop-engineering/main/loop-run-log.md');
const text = await res.text();

// Parse JSON lines from the markdown file
const lines = text.split('\n');
const data = [];
for (const line of lines) {
if (line.trim().startsWith('{')) {
try {
data.push(JSON.parse(line));
} catch (e) {}
}
}

if (data.length === 0) return;

// X-axis: dates
const labels = data.map(d => new Date(d.run_id).toLocaleDateString(undefined, { month: 'short', day: 'numeric' }));

const scores = data.map(d => d.readiness_score || 0);
const tokens = data.map((d, i) => {
let sum = 0;
for (let j = 0; j <= i; j++) sum += (data[j].tokens_estimate || 0);
return sum;
});
const automatedRuns = data.map(d => d.outcome === 'escalated' ? 0 : 1);
const escalatedRuns = data.map(d => d.outcome === 'escalated' ? 1 : 0);

// Chart options helpers
const chartOpts = (yCallback) => ({
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
y: { min: 0, grid: { color: '#2a3b52' }, ticks: { color: '#8e9baebd', callback: yCallback } },
x: { grid: { display: false }, ticks: { color: '#8e9baebd', maxTicksLimit: 10 } }
}
});

const ctxScore = document.getElementById('scoreChart');
if (ctxScore) {
new Chart(ctxScore, {
type: 'line',
data: {
labels,
datasets: [{ data: scores, borderColor: '#3ee8c5', backgroundColor: 'rgba(62, 232, 197, 0.1)', borderWidth: 2, tension: 0.1, fill: true }]
},
options: { ...chartOpts(), scales: { ...chartOpts().scales, y: { ...chartOpts().scales.y, max: 100 } } }
});
}

const ctxToken = document.getElementById('tokenChart');
if (ctxToken) {
new Chart(ctxToken, {
type: 'line',
data: {
labels,
datasets: [{ data: tokens, borderColor: '#5b9dff', backgroundColor: 'rgba(91, 157, 255, 0.15)', borderWidth: 2, tension: 0.3, fill: true }]
},
options: chartOpts(v => v >= 1000 ? (v/1000) + 'k' : v)
});
}

const ctxEscalation = document.getElementById('escalationChart');
if (ctxEscalation) {
new Chart(ctxEscalation, {
type: 'bar',
data: {
labels,
datasets: [
{ label: 'Automated', data: automatedRuns, backgroundColor: '#3ee8c5' },
{ label: 'Escalated', data: escalatedRuns, backgroundColor: '#ffb347' }
]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { stacked: true, grid: { display: false }, ticks: { color: '#8e9baebd', maxTicksLimit: 10 } },
y: { stacked: true, beginAtZero: true, grid: { color: '#2a3b52' }, ticks: { color: '#8e9baebd', stepSize: 1 } }
}
}
});
}
} catch (e) {
console.error('Failed to render telemetry:', e);
}
}

// Boot
document.addEventListener('DOMContentLoaded', () => {
setupMobileNav();
setupPatternPicker();
setupSimulator();
renderTelemetry();
});
</script>

Expand Down
16 changes: 15 additions & 1 deletion examples/github-actions/ci-sweeper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,21 @@ jobs:
echo "- URL: ${{ github.event.workflow_run.html_url }}" >> "$FILE"
echo "- Loop action: pending agent invocation" >> "$FILE"

- name: Circuit breaker check
id: circuit_breaker
run: |
npx --yes @cobusgreyling/loop-context --check --ledger loop-ledger.json \
--budget-from-pattern ci-sweeper --budget-level L2 || echo "tripped=true" >> "$GITHUB_OUTPUT"
continue-on-error: true

- name: Invoke fix agent
if: steps.circuit_breaker.outputs.tripped != 'true'
run: |
echo "::notice::Wire to agent: classify failure, worktree fix, verifier, open PR."
echo "See patterns/ci-sweeper.md and docs/safety.md"
echo "See patterns/ci-sweeper.md and docs/safety.md"

- name: Escalate (circuit breaker tripped)
if: steps.circuit_breaker.outputs.tripped == 'true'
run: |
echo "::warning::Circuit breaker tripped — same failure recurred or attempt cap reached."
echo "Escalating to human instead of retrying. See docs/safety.md#human-gates-required."
15 changes: 14 additions & 1 deletion examples/github-actions/dependency-sweeper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,21 @@ jobs:
with:
node-version: '22'

- name: Circuit breaker check
id: circuit_breaker
run: |
npx --yes @cobusgreyling/loop-context --check --ledger loop-ledger.json \
--budget-from-pattern dependency-sweeper --budget-level L2 || echo "tripped=true" >> "$GITHUB_OUTPUT"
continue-on-error: true

- name: Placeholder — wire to your agent runtime
if: steps.circuit_breaker.outputs.tripped != 'true'
run: |
echo "Run dependency-triage (npm audit / outdated)."
echo "Patch-only fixes in worktree with verifier."
echo "Update dependency-sweeper-state.md — escalate majors."
echo "Update dependency-sweeper-state.md — escalate majors."

- name: Escalate (circuit breaker tripped)
if: steps.circuit_breaker.outputs.tripped == 'true'
run: |
echo "::warning::Circuit breaker tripped for this package — see docs/safety.md#human-gates-required."
3 changes: 3 additions & 0 deletions loop-run-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ Append one entry per run. Prune entries older than 30 days.
{"run_id":"2026-07-17T09:41:37Z","pattern":"daily-triage","duration_s":4,"items_found":1,"actions_taken":1,"escalations":0,"tokens_estimate":52000,"readiness_score":100,"outcome":"report-only","workflow_run":"29570867800"}
{"run_id":"2026-07-20T08:58:36Z","pattern":"daily-triage","duration_s":8,"items_found":1,"actions_taken":1,"escalations":0,"tokens_estimate":52000,"readiness_score":100,"outcome":"report-only","workflow_run":"29729689810"}
{"run_id":"2026-07-21T08:49:11Z","pattern":"daily-triage","duration_s":6,"items_found":1,"actions_taken":1,"escalations":0,"tokens_estimate":52000,"readiness_score":100,"outcome":"report-only","workflow_run":"29815743998"}
{"run_id":"2026-07-21T12:08:44Z","pattern":"daily-triage","duration_s":180,"items_found":6,"actions_taken":2,"escalations":4,"tokens_estimate":35000,"readiness_score":100,"outcome":"report-only","note":"re-curate after #334; open 315-318,321,323"}
{"run_id":"2026-07-21T12:38:33Z","pattern":"daily-triage","duration_s":90,"items_found":7,"actions_taken":1,"escalations":5,"tokens_estimate":25000,"readiness_score":100,"outcome":"report-only","note":"new PR #335 loop-context breaker; open 315-318,321,323,335"}
{"run_id":"2026-07-21T14:11:50Z","pattern":"daily-triage","duration_s":600,"items_found":7,"actions_taken":5,"escalations":2,"tokens_estimate":40000,"readiness_score":100,"outcome":"report-only","note":"PR triage: merge 316/318/335; close 315; changes-requested 317/321"}
Loading
Loading