Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c941af6
docs: freeze GitNexus and Brain MCP reference slice
plugmil Sep 30, 2026
584f381
feat(swarm): validate wave files before enqueueing
plugmil Oct 3, 2026
af5b5fc
feat(swarm): add the model-free fleet report
plugmil Oct 3, 2026
2807b06
docs: add dauermodus.md for PlugBrain 0.6
plugmil Oct 3, 2026
8cc2233
feat: read-only lead tick that computes one lead cycle from the store
plugmil Oct 3, 2026
9a0636b
feat(coord): add nvidia model family with nemotron prefixes
plugmil Oct 3, 2026
57a7d80
feat: quota-pool show reports policy, workers and reservations
plugmil Oct 3, 2026
e17ec0a
Make task delivery idempotent: duplicate delivery with same evidence …
plugmil Oct 3, 2026
827e0d1
fix(B17): mark worker needs-task when no current task at death
plugmil Oct 3, 2026
b64e47d
fix: bind dependency release to the claim and block failed launches
plugmil Oct 3, 2026
323ae1d
B13-OWNER-STOP: owner stop/resume per agent and global
plugmil Oct 3, 2026
d4f62c4
fix: wave check runs without Brain-DB (skip schema & supervisor attempt)
plugmil Oct 3, 2026
90e98fc
merge: B03-FAMILY-NVIDIA (Review PASS 9a0636b7ee)
Oct 3, 2026
23ad774
merge: B12-IDEMPOTENT-DELIVER (Review PASS e17ec0abca)
Oct 3, 2026
43528e4
merge: B13-OWNER-STOP (Review PASS 323ae1dee5)
Oct 3, 2026
92f9f49
merge: B17-TURNSTART-RACE (Review PASS 827e0d161c)
Oct 3, 2026
283f430
merge: B22-LAUNCHERR-DEPS (Review PASS b64e47dde0)
Oct 3, 2026
b7e91c2
merge: FB-G03-DOCS-DAUERMODUS (Review PASS 2807b06f88)
Oct 3, 2026
cee1d77
Revert "merge: B17-TURNSTART-RACE (Review PASS 827e0d161c)"
Oct 3, 2026
834639e
merge: FB-H3-LEAD-TICK (Review PASS 8cc2233a13)
Oct 3, 2026
593618b
M09-BENCH: Add PlugHarness benchmark questions and parity runner
plugmil Oct 3, 2026
7cdb823
B01-FAILURE-CLASS: switch classifySupervisorFailure to structured log…
plugmil Oct 3, 2026
1ed61db
B10: Artifact binding für Delivery
plugmil Oct 3, 2026
bbfef02
merge: B18-POOL-VISIBILITY (Review PASS 57a7d8053c)
Oct 3, 2026
9e8a1d4
B15-REFEED-SCHEDULER: Add mandate validation via plan_ref for unaddre…
plugmil Oct 3, 2026
a39b7b3
merge: M09-BENCH (Review PASS 593618bdb8)
Oct 3, 2026
02b6029
fix: runner start without current task => needs-task, supervisor cont…
plugmil Oct 3, 2026
9639bef
Reapply "merge: B17-TURNSTART-RACE (Review PASS 827e0d161c)"
Oct 3, 2026
e3d583a
merge: B17-TURNSTART-RACE + W2-B17-FIX (Lead-Test)
Oct 3, 2026
830cc31
merge: W2-B15-REFEED (Review PASS 9e8a1d40e7)
Oct 3, 2026
22b2bc5
Revert "merge: W2-B15-REFEED (Review PASS 9e8a1d40e7)"
Oct 3, 2026
feacc9a
Merge branch 'w01/b16-report-cli-20261003' into w02/int-seq-20261003
plugmil Oct 3, 2026
d8b1b9b
Merge branch 'w01/fb-h2-wave-check-20261003' into w02/int-seq-20261003
plugmil Oct 3, 2026
8daea8c
Merge branch 'w01/b10-artifact-binding-20261003' into w02/int-seq-202…
plugmil Oct 3, 2026
801bb0e
Merge branch 'w01/b01-failure-class-20261003' into w02/int-seq-20261003
plugmil Oct 3, 2026
048400b
Reapply "merge: W2-B15-REFEED (Review PASS 9e8a1d40e7)"
plugmil Oct 3, 2026
a0f9ede
Merge commit '22b2bc5' into w03/int-seq-fix-20261003
plugmil Oct 3, 2026
1439dcc
Fix swarm CLI usage documentation and remove test debug outputs
plugmil Oct 3, 2026
4917bc9
merge: W3-INT-SEQ-FIX (B16, FB-H2-WAVE-CHECK, B10, B01 + CLI-Usage-Fi…
plugmil Oct 3, 2026
25538d3
fix: make mandate check and single-claim rule optional in claimNextTask
plugmil Oct 3, 2026
1b6af66
merge: W3-B15-FIX (B15 Mandat/Ein-Claim nur per Option, Standard wie …
plugmil Oct 3, 2026
e4ced07
Merge remote-tracking branch 'github/main' into release/0.6.0-rc.1
plugmil Oct 3, 2026
b958b2d
Merge remote-tracking branch 'github/feat/m09-reference-20260930' int…
plugmil Oct 3, 2026
2735a09
release: 0.6.0-rc.1 — version, changelog, release notes, README status
plugmil Oct 3, 2026
e78ece1
release: add 0.6.0-rc.1 release notes
plugmil Oct 3, 2026
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
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
},
"metadata": {
"description": "PlugBrain — local project and code memory for AI agents",
"version": "0.5.0-dev.1"
"version": "0.6.0-rc.1"
},
"plugins": [
{
"name": "plugbrain",
"source": "./",
"description": "Ask the brain first: AST code intelligence, Obsidian-style notes and agent coordination for this repository, served locally over MCP.",
"version": "0.5.0-dev.1",
"version": "0.6.0-rc.1",
"license": "MIT",
"category": "productivity",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "plugbrain",
"version": "0.5.0-dev.1",
"version": "0.6.0-rc.1",
"description": "Local project and code memory for AI agents: AST code intelligence, Obsidian-style notes and multi-agent coordination, asked through MCP.",
"author": {
"name": "litbitrim"
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ All notable changes to PlugBrain are documented here.
The format follows [Keep a Changelog](https://keepachangelog.com/) and the
project adheres to [Semantic Versioning](https://semver.org/).

## [0.6.0-rc.1] — 2026-10-03 (release candidate)

Continuous mode: the parts of the overnight loop that are built and tested.
Full notes: `release/RELEASE-NOTES-v0.6.0-rc.1.md`.

### Added

- `plugbrain swarm report`, `plugbrain swarm wave check`, `plugbrain swarm lead-tick` and `plugbrain swarm quota-pool show`.
- Owner stop that survives restarts and is never lifted by the watchdog.
- Opt-in mandate scheduling and single-claim mode for `claimNextTask`; the default is unchanged.
- Continuous-mode guide, GitNexus / Brain MCP reference slice and `bench/m09-parity.mjs`.

### Fixed

- Idempotent delivery; launch errors no longer release dependents; a worker without a current task is set to `needs-task` instead of `blocked`.
- Deliveries are bound to task, attempt, worktree and full commit hash.
- Supervisor failures are classified from structured signals, not log words.
- NVIDIA-hosted model families are recognised for review independence.

## [0.5.0-dev.1] — 2026-09-30 (development candidate)

This branch carries the local PlugBrain 0.5 source candidate onto the public
Expand Down
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,22 @@ cloud, no telemetry. MIT licensed.

## Status

- 0.3.1 is the first published release. It is developed on Windows; macOS and
Linux run the same tests and packaging checks in CI.
- PlugBrain's own development runs on it. On 26 September 2026 one board
coordinated Claude Code, three Codex CLI workers and four Freebuff workers on
this repository.
- **0.6.0-rc.1** is the current release candidate (continuous mode: report,
wave check, lead tick, owner stop, idempotent and artifact-bound delivery).
See the [changelog](CHANGELOG.md) and the
[release notes](release/RELEASE-NOTES-v0.6.0-rc.1.md). The latest published
build is 0.3.1; newer builds follow once the candidate passes CI on all
three platforms.
- It is developed on Windows; macOS and Linux run the same tests and packaging
checks in CI.
- PlugBrain's own development runs on it: on 3 October 2026 one board drove
eight headless NVIDIA-hosted workers and several Freebuff workers through
waves of prepared tasks overnight.
- The web UI and the output of `plugbrain swarm` are in German for now. The
other commands, the MCP tools and all documentation are in English.
- Not there yet: the store keeps only each agent's latest turn, so there is no
turn history to replay, and worktrees of merged branches are not removed
automatically. Both are being built.
other commands, the MCP tools and the documentation are in English.
- Not there yet: dependents are still released when a predecessor's holder
reports `needs-task` (a strict, delivery-only rule is in review), and the
supervisor exits after 24 empty polls instead of idling.

## How agents work together

Expand Down
271 changes: 271 additions & 0 deletions bench/m09-parity.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
/**
* M09 Parity Benchmark Runner
*
* Compares PlugBrain vs GitNexus accuracy, latency, and index footprint
* across the frozen benchmark corpora.
*
* Usage:
* BENCH_REPOS_ROOT=/path/to/corpora node bench/m09-parity.mjs [--dry-run]
*
* --dry-run validates questions, schemas, and paths without running
* full benchmarks. Exit 0 on success.
*/

import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { BENCH_V2_DIR, QUESTIONS_DIR, RAW_DIR, REPOS_FILE, loadRepos, requireReposRoot } from './v2/paths.mjs';

const DRY_RUN = process.argv.includes('--dry-run');

function validateRepos() {
const repos = JSON.parse(readFileSync(REPOS_FILE, 'utf8')).repos;
if (!repos || !Array.isArray(repos)) {
throw new Error('Invalid repos.json: repos array missing');
}
const issues = [];
for (const repo of repos) {
if (!repo.name || !repo.description) {
issues.push(`${repo.name || 'unknown'} missing name/description`);
}
if (repo.name === 'plugharness') {
// Accept main branch for plugharness
if (repo.commit !== 'main' && !repo.commit?.startsWith('1') && !repo.commit?.length > 7) {
issues.push(`plugharness commit format looks wrong: ${repo.commit}`);
}
}
}
if (issues.length) {
throw new Error(`Repos validation failed: ${issues.join('; ')}`);
}
}

function validateQuestions() {
const dirs = existsSync(QUESTIONS_DIR) ? [...new Set([QUESTIONS_DIR])] : [];
const requiredRepos = ['mcpz', 'plugmedia', 'cowork', 'plugengine', 'plugharness'];
const missing = [];

for (const name of requiredRepos) {
const file = join(QUESTIONS_DIR, `${name}.json`);
if (!existsSync(file)) {
missing.push(file);
continue;
}
let questions;
try {
questions = JSON.parse(readFileSync(file, 'utf8'));
} catch (e) {
throw new Error(`Invalid JSON in ${file}: ${e.message}`);
}
if (!Array.isArray(questions)) {
throw new Error(`${file} does not contain an array`);
}
if (questions.length < 10) {
throw new Error(`${file} has only ${questions.length} questions (expected >=10)`);
}
for (const q of questions) {
if (!q.id || !q.type || !q.question || !q.query_param || !q.expected) {
throw new Error(`${file}:${q.id || 'unknown'} missing required fields`);
}
if (!q.expected.path || !q.expected.symbol) {
throw new Error(`${file}:${q.id} expected.path/symbol missing`);
}
}
}

if (missing.length) {
throw new Error(`Missing question files: ${missing.join(', ')}`);
}
}

function checkRawDir() {
if (!existsSync(RAW_DIR)) {
console.log('Creating raw directory...');
// Will be created on first write
}
}

function loadExistingResults(tool) {
const results = {};
try {
const summaryFile = join(RAW_DIR, `${tool}-summary.json`);
if (existsSync(summaryFile)) {
const summary = JSON.parse(readFileSync(summaryFile, 'utf8'));
results[tool] = summary;
results[`${tool}Repos`] = summary.repos || [];
}
} catch (e) {
console.warn(`Could not load ${tool} results: ${e.message}`);
}
return results;
}

function computeParityMetrics(plugbrain, gitnexus) {
const parity = {
timestamp: new Date().toISOString(),
totalQuestionsPB: 0,
totalQuestionsGN: 0,
totalHitsPB: 0,
totalHitsGN: 0,
accuracyPB: 0,
accuracyGN: 0,
accuracyDelta: 0,
latencyHitRatioPB: 0,
latencyHitRatioGN: 0,
indexSizeDeltaBytes: 0,
repos: []
};

const pbRepos = new Map((plugbrain.repos || []).map(r => [r.repo, r]));
const gnRepos = new Map((gitnexus.repos || []).map(r => [r.repo, r]));

let totalLatenciesPB = [];
let totalLatenciesGN = [];
let totalIndexSizePB = 0;
let totalIndexSizeGN = 0;

for (const [repoName, gnRepo] of gnRepos) {
const pbRepo = pbRepos.get(repoName);
if (!pbRepo) continue;

const hitDelta = (pbRepo.hitCount - gnRepo.hitCount);
const accPB = pbRepo.accuracy || 0;
const accGN = gnRepo.accuracy || 0;
const latencyDelta = (pbRepo.latencyP50Ms || 0) - (gnRepo.latencyP50Ms || 0);

parity.repos.push({
repo: repoName,
commit: pbRepo.commit,
questionsPB: pbRepo.questionCount,
questionsGN: gnRepo.questionCount,
hitsPB: pbRepo.hitCount,
hitsGN: gnRepo.hitCount,
accuracyPB: accPB,
accuracyGN: accGN,
accuracyDelta: Math.round((accPB - accGN) * 10) / 10,
latencyP50PB: pbRepo.latencyP50Ms,
latencyP50GN: gnRepo.latencyP50Ms,
latencyDeltaP50: latencyDelta,
indexSizePBBytes: pbRepo.indexSizeBytes,
indexSizeGNBytes: gnRepo.indexSizeBytes,
indexSizeDeltaBytes: (pbRepo.indexSizeBytes || 0) - (gnRepo.indexSizeBytes || 0)
});

parity.totalQuestionsPB += pbRepo.questionCount || 0;
parity.totalQuestionsGN += gnRepo.questionCount || 0;
parity.totalHitsPB += pbRepo.hitCount || 0;
parity.totalHitsGN += gnRepo.hitCount || 0;
totalIndexSizePB += pbRepo.indexSizeBytes || 0;
totalIndexSizeGN += gnRepo.indexSizeBytes || 0;
}

if (parity.totalQuestionsPB > 0) {
parity.accuracyPB = Math.round((parity.totalHitsPB / parity.totalQuestionsPB) * 1000) / 10;
}
if (parity.totalQuestionsGN > 0) {
parity.accuracyGN = Math.round((parity.totalHitsGN / parity.totalQuestionsGN) * 1000) / 10;
}
parity.accuracyDelta = Math.round((parity.accuracyPB - parity.accuracyGN) * 10) / 10;
parity.indexSizeDeltaBytes = totalIndexSizePB - totalIndexSizeGN;

return parity;
}

async function run() {
console.log('M09 Parity Benchmark Validator');
console.log('================================');

if (DRY_RUN) {
console.log('\n[DRY RUN] Checking configuration...');
} else {
console.log('\n[VALIDATING] Checking configuration...');
}

// Validate environment
if (!process.env.BENCH_REPOS_ROOT) {
throw new Error('BENCH_REPOS_ROOT environment variable is required');
}
requireReposRoot();

// Validate repos
validateRepos();
console.log('✓ repos.json valid');

// Validate questions
validateQuestions();
console.log('✓ questions valid (all repos have >=10 questions)');

// Check raw directory
checkRawDir();
console.log('✓ raw directory exists');

// Load existing results
const plugbrain = loadExistingResults('plugbrain');
const gitnexus = loadExistingResults('gitnexus');

if (!DRY_RUN) {
if (!plugbrain || !gitnexus) {
console.warn('\n⚠ Warning: Existing benchmark results not found.');
console.warn('Run bench/v2/run-plugbrain.mjs and run-gitnexus.mjs first.');
console.warn('Continuing with validation only...');
} else {
console.log('✓ Found existing benchmark results');

// Compute parity metrics
const parity = computeParityMetrics(plugbrain, gitnexus);

// Write parity report
const parityFile = join(RAW_DIR, 'm09-parity-report.json');
writeFileSync(parityFile, JSON.stringify(parity, null, 2));

// Summary output
console.log('\n================================');
console.log('Parity Report Summary');
console.log('================================');
console.log(`Total Questions (PlugBrain): ${parity.totalQuestionsPB}`);
console.log(`Total Questions (GitNexus): ${parity.totalQuestionsGN}`);
console.log(`Accuracy (PlugBrain): ${parity.accuracyPB}%`);
console.log(`Accuracy (GitNexus): ${parity.accuracyGN}%`);
console.log(`Accuracy Delta: ${parity.accuracyDelta > 0 ? '+' : ''}${parity.accuracyDelta}%`);
console.log(`Index Size Delta: ${parity.indexSizeDeltaBytes > 0 ? '+' : ''}${(parity.indexSizeDeltaBytes / 1024 / 1024).toFixed(2)} MB`);

for (const repo of parity.repos) {
const deltaIcon = repo.accuracyDelta >= 0 ? '▲' : '▼';
console.log(` ${repo.repo}: PB ${repo.accuracyPB}% / GN ${repo.accuracyGN}% (${deltaIcon} ${repo.accuracyDelta > 0 ? '+' : ''}${repo.accuracyDelta}%)`);
}

console.log(`\nParity report saved to: ${parityFile}`);
}
} else {
console.log('\n[DOCKER RUN] All validation checks passed');
}

console.log('\n✓ M09 Parity Benchmark validation complete');

// Schema documentation
console.log('\n--- Schema Documentation ---');
console.log('Parity report schema:');
console.log({
tool: 'm09-parity',
repos: ['name', 'commit', 'description'],
questionsFormat: {
id: 'string',
type: 'definition|callers|impact|dataflow|config|entrypoint|docs_notes|rename_impact',
question: 'string',
query_param: 'string',
expected: {
path: 'string',
symbol: 'string',
kind: 'string',
details: 'string',
expected_targets: ['string'] // optional
}
}
});

process.exitCode = 0;
}

run().catch(err => {
console.error('\n✗ Validation failed:', err.message);
process.exit(1);
});
Loading
Loading