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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ scripts/install-vscode-active-agents-extension.js
oh-my-codex/
.omx/state/agent-file-locks.json
# multiagent-safety:END
apps/hivemind-demo/data/runs/*
!apps/hivemind-demo/data/runs/.gitkeep
129 changes: 129 additions & 0 deletions apps/hivemind-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Hivemind Demo

Minimal local multi-agent MVP for bounded software-task execution.

This package simulates a small hivemind with five deterministic agents:

- `Coordinator`
- `Researcher`
- `Builder`
- `Reviewer`
- `Verifier`

Each run writes shared JSON state after every step, compacts progress into checkpoints, and requires verifier approval before returning success.

## File Tree

```text
apps/hivemind-demo/
data/
runs/
src/
agents/
coordinator.ts
researcher.ts
builder.ts
reviewer.ts
verifier.ts
core/
orchestrator.ts
state.ts
checkpoint.ts
types.ts
cli/
index.ts
utils/
logger.ts
ids.ts
index.ts
test/
orchestrator.test.ts
package.json
tsconfig.json
README.md
```

## What It Does

- Accepts one task from the CLI
- Creates a bounded plan
- Runs research, build, review, and verification phases
- Writes `state.json` after every phase
- Creates checkpoint summaries every few steps
- Stops on verifier approval, retry exhaustion, or max-turn failure

Persisted run output lives under `data/runs/<run-id>/`:

- `state.json`
- `checkpoints/*.json`
- `final-output.json` when verification succeeds

## Run It

From the package directory:

```sh
pnpm install
pnpm run demo
pnpm build
node dist/cli/index.js "Create a local TypeScript CLI that plans, reviews, and verifies a task with checkpoint summaries."
```

Or point output somewhere disposable:

```sh
node dist/cli/index.js --data-dir /tmp/hivemind-runs --demo
```

## Example Usage

```sh
node dist/cli/index.js "Build a local TypeScript CLI with JSON state, checkpoints, README, and verifier approval."
```

Example output:

```text
[hivemind] coordinator/plan: Coordinator planned a 4-step hivemind loop.
[hivemind] researcher/research: Researcher captured 5 constraints and 4 focus areas.
[hivemind] builder/build: Builder produced attempt 1 with 16 files in scope.
[hivemind] reviewer/review: Reviewer approved builder output.
[hivemind] coordinator/decide: Coordinator sends approved build to verifier.
[hivemind] verifier/verify: Verifier approved final output.
Run: run-2026-04-23T18-00-00-000Z
Status: completed
Run dir: /.../apps/hivemind-demo/data/runs/run-2026-04-23T18-00-00-000Z
Checkpoints: 3
```

## Demo Flow

1. Coordinator creates a bounded plan and subtasks.
2. Researcher extracts constraints, assumptions, and focus areas from the task text.
3. Builder turns that research into a file tree, implementation plan, test plan, and checkpoint policy.
4. Reviewer checks for missing required files, tests, and compaction rules.
5. Coordinator decides whether to retry the builder or continue.
6. Verifier approves only when plan, artifacts, and checkpoints exist.

## Limitations

- Agent behavior is deterministic. No real LLM reasoning is exercised.
- Execution is sequential. There is no parallel worker scheduling yet.
- Tool use is not wired in. The system only simulates agent decisions.
- Checkpoints are simple summaries, not semantic compression or retrieval.

## Extending With Real Model / Tool Calls

The extension points already exist in `src/core/types.ts`:

- `ModelProvider`
- `ToolRunner`

To replace the deterministic agents later:

1. Implement a `ModelProvider` that turns agent prompts + state into model output.
2. Implement a `ToolRunner` for file, web, or code tools.
3. Swap the current agent bodies to call those interfaces instead of heuristic rules.
4. Keep the checkpoint contract unchanged so coordination cost stays bounded.

That keeps the MVP shape stable while the inner reasoning surface becomes real.
Empty file.
22 changes: 22 additions & 0 deletions apps/hivemind-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@cavemem/hivemind-demo",
"version": "0.0.0",
"private": true,
"license": "MIT",
"type": "module",
"main": "./dist/index.js",
"bin": {
"cavemem-hivemind-demo": "./dist/cli/index.js"
},
"scripts": {
"build": "tsup src/index.ts src/cli/index.ts --format esm --dts --clean",
"demo": "pnpm build && node dist/cli/index.js --demo",
"test": "vitest run",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"tsup": "^8.3.5",
"typescript": "^5.6.3",
"vitest": "^2.1.5"
}
}
91 changes: 91 additions & 0 deletions apps/hivemind-demo/src/agents/builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { findLatestArtifact } from '../core/state.js';
import type {
Agent,
AgentInput,
AgentResult,
BuildArtifactContent,
ResearchArtifactContent,
ReviewArtifactContent,
RunState,
} from '../core/types.js';

const BASE_FILE_TREE = [
'src/agents/coordinator.ts',
'src/agents/researcher.ts',
'src/agents/builder.ts',
'src/agents/reviewer.ts',
'src/agents/verifier.ts',
'src/core/orchestrator.ts',
'src/core/state.ts',
'src/core/checkpoint.ts',
'src/core/types.ts',
'src/cli/index.ts',
'src/index.ts',
'src/utils/logger.ts',
'src/utils/ids.ts',
'test/orchestrator.test.ts',
'README.md',
'data/runs/.gitkeep',
];

export class BuilderAgent implements Agent {
readonly name = 'Builder';
readonly role = 'builder' as const;

run(input: AgentInput, state: RunState): AgentResult {
const research = findLatestArtifact<ResearchArtifactContent>(state, 'research')?.content;
const priorReview = findLatestArtifact<ReviewArtifactContent>(state, 'review')?.content;
const revisionNotes =
input.attempt > 1 && priorReview ? priorReview.requiredFixes.map((issue) => `Address review feedback: ${issue}`) : [];

const content: BuildArtifactContent = {
fileTree: [...BASE_FILE_TREE],
implementationSteps: [
'Define core types for run state, subtasks, artifacts, checkpoints, and final output.',
'Persist `state.json` after every agent step under `data/runs/<run-id>/`.',
'Run coordinator -> researcher -> builder -> reviewer -> verifier with max-turn and retry guards.',
'Create compact checkpoints every few steps so workers share only Goal / Done / Blocker / Next.',
'Require verifier approval before final success is emitted.',
],
testPlan: [
'Happy path: orchestrator completes a bounded task and writes checkpoints.',
'Failure path: reviewer rejects a build with no test plan or checkpoint policy.',
'CLI path: the command prints run status, result, and run directory.',
],
checkpointPolicy: [
'Default checkpoint interval = 2 agent steps.',
'Checkpoint payload carries Goal, Done, Current blocker, and Next batch only.',
'Coordinator decisions consume checkpoints and active blockers instead of raw history.',
],
notes: unique([
...(research?.recommendedFocus ?? []),
...revisionNotes,
'Provider and tool interfaces stay swappable for future real integrations.',
]),
};

return {
status: 'completed',
summary: `Builder produced attempt ${input.attempt} with ${content.fileTree.length} files in scope.`,
details: [
content.implementationSteps[0] ?? '',
content.implementationSteps[1] ?? '',
content.testPlan[0] ?? '',
].filter(Boolean),
artifact: {
type: 'build',
label: input.attempt > 1 ? `build-attempt-${input.attempt}` : 'initial-build',
content,
},
markSubtasks: [
{ id: 'build', status: 'completed', note: `Builder attempt ${input.attempt} ready for review.` },
{ id: 'review', status: 'in_progress', note: 'Reviewing current build.' },
],
replaceBlockers: [],
};
}
}

function unique(values: string[]): string[] {
return [...new Set(values)];
}
Loading
Loading