Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3b8ad61
LoRA training pipeline commands + adapter entity persistence
joelteply Feb 17, 2026
868c73a
Academy Dojo: dual-sentinel teacher/student architecture
joelteply Feb 17, 2026
9887bcf
Sentinel interpolation engine: multi-pass nesting, JSON traversal, lo…
joelteply Feb 17, 2026
896b1f3
Sentinel lifecycle: entity persistence, persona ownership, escalation…
joelteply Feb 17, 2026
a092095
Sentinel memory integration, trigger service, and pattern recall
joelteply Feb 17, 2026
d6120be
Phenotype validation + quality gating for Academy student pipeline
joelteply Feb 17, 2026
06c686b
Dynamic composition, LRU paging, and remediation loop
joelteply Feb 17, 2026
81ad574
Multi-persona competition + gap analysis for Academy Phase D
joelteply Feb 17, 2026
bce6f16
Purge Ollama: complete removal from types, runtime, comments, and tests
joelteply Feb 17, 2026
2121127
Fix JTAGClient connection hang + Academy Dojo integration tests
joelteply Feb 17, 2026
e05e05d
Eliminate Academy Dojo technical debt: type safety, imports, READMEs
joelteply Feb 17, 2026
8240605
Replace as-any casts with typed executors across all genome commands
joelteply Feb 17, 2026
5328e8f
Wire LoRA adapters into Candle inference + unified model config
joelteply Feb 17, 2026
ec0a33d
Knowledge Synthesis system: source-agnostic learning + benchmarks
joelteply Feb 18, 2026
f600a43
Route Python training through Rust sentinel process management
joelteply Feb 18, 2026
2946f9c
Async training architecture: SentinelEventBridge + dual-mode genome/t…
joelteply Feb 18, 2026
db18c28
Fix integration tests: sync pipeline mode, collection routing, respon…
joelteply Feb 18, 2026
815b40c
Add LearningScheduler: RTOS-style periodic training coordinator
joelteply Feb 18, 2026
adf74b7
BenchmarkEntity + CodingChallengePipeline + sentinelExecute output fix
joelteply Feb 18, 2026
5cac1cf
claude forgot these
joelteply Feb 18, 2026
5402cc7
Fix RAG token budget and eliminate fallback defaults across AI pipeline
joelteply Feb 18, 2026
5494203
ModelBackend trait, academy pipelines, domain classifier, candle fixes
joelteply Feb 18, 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
721 changes: 721 additions & 0 deletions docs/MLX-LORA-RESEARCH.md

Large diffs are not rendered by default.

38 changes: 37 additions & 1 deletion src/debug/jtag/browser/generated.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Browser Structure Registry - Auto-generated
*
* Contains 11 daemons and 205 commands and 2 adapters and 28 widgets.
* Contains 11 daemons and 211 commands and 2 adapters and 28 widgets.
* Generated by scripts/generate-structure.ts - DO NOT EDIT MANUALLY
*/

Expand Down Expand Up @@ -124,9 +124,15 @@ import { FileAppendBrowserCommand } from './../commands/file/append/browser/File
import { FileLoadBrowserCommand } from './../commands/file/load/browser/FileLoadBrowserCommand';
import { FileMimeTypeBrowserCommand } from './../commands/file/mime-type/browser/FileMimeTypeBrowserCommand';
import { FileSaveBrowserCommand } from './../commands/file/save/browser/FileSaveBrowserCommand';
import { GenomeAcademyCompetitionBrowserCommand } from './../commands/genome/academy-competition/browser/GenomeAcademyCompetitionBrowserCommand';
import { GenomeAcademySessionBrowserCommand } from './../commands/genome/academy-session/browser/GenomeAcademySessionBrowserCommand';
import { GenomeBatchMicroTuneBrowserCommand } from './../commands/genome/batch-micro-tune/browser/GenomeBatchMicroTuneBrowserCommand';
import { GenomeDatasetPrepareBrowserCommand } from './../commands/genome/dataset-prepare/browser/GenomeDatasetPrepareBrowserCommand';
import { GenomeDatasetSynthesizeBrowserCommand } from './../commands/genome/dataset-synthesize/browser/GenomeDatasetSynthesizeBrowserCommand';
import { GenomeJobCreateBrowserCommand } from './../commands/genome/job-create/browser/GenomeJobCreateBrowserCommand';
import { GenomeJobStatusBrowserCommand } from './../commands/genome/job-status/browser/GenomeJobStatusBrowserCommand';
import { GenomeTrainBrowserCommand } from './../commands/genome/train/browser/GenomeTrainBrowserCommand';
import { GenomeTrainingPipelineBrowserCommand } from './../commands/genome/training-pipeline/browser/GenomeTrainingPipelineBrowserCommand';
import { HelpBrowserCommand } from './../commands/help/browser/HelpBrowserCommand';
import { IndicatorBrowserCommand } from './../commands/indicator/browser/IndicatorBrowserCommand';
import { InferenceGenerateBrowserCommand } from './../commands/inference/generate/browser/InferenceGenerateBrowserCommand';
Expand Down Expand Up @@ -852,11 +858,31 @@ export const BROWSER_COMMANDS: CommandEntry[] = [
className: 'FileSaveBrowserCommand',
commandClass: FileSaveBrowserCommand
},
{
name: 'genome/academy-competition',
className: 'GenomeAcademyCompetitionBrowserCommand',
commandClass: GenomeAcademyCompetitionBrowserCommand
},
{
name: 'genome/academy-session',
className: 'GenomeAcademySessionBrowserCommand',
commandClass: GenomeAcademySessionBrowserCommand
},
{
name: 'genome/batch-micro-tune',
className: 'GenomeBatchMicroTuneBrowserCommand',
commandClass: GenomeBatchMicroTuneBrowserCommand
},
{
name: 'genome/dataset-prepare',
className: 'GenomeDatasetPrepareBrowserCommand',
commandClass: GenomeDatasetPrepareBrowserCommand
},
{
name: 'genome/dataset-synthesize',
className: 'GenomeDatasetSynthesizeBrowserCommand',
commandClass: GenomeDatasetSynthesizeBrowserCommand
},
{
name: 'genome/job-create',
className: 'GenomeJobCreateBrowserCommand',
Expand All @@ -867,6 +893,16 @@ export const BROWSER_COMMANDS: CommandEntry[] = [
className: 'GenomeJobStatusBrowserCommand',
commandClass: GenomeJobStatusBrowserCommand
},
{
name: 'genome/train',
className: 'GenomeTrainBrowserCommand',
commandClass: GenomeTrainBrowserCommand
},
{
name: 'genome/training-pipeline',
className: 'GenomeTrainingPipelineBrowserCommand',
commandClass: GenomeTrainingPipelineBrowserCommand
},
{
name: 'help',
className: 'HelpBrowserCommand',
Expand Down
17 changes: 10 additions & 7 deletions src/debug/jtag/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,11 @@ async function main() {

// Execute command with command-specific timeout
try {
// AI commands need longer timeout due to queue + generation time
// Genome commands can take longer for training operations
// Interface commands (screenshot) may need to wait for html2canvas rendering
// Inference commands (inference/generate) need time for local model generation
// Extract --timeout from params (CLI-level override, not a command parameter)
const userTimeoutMs = params.timeout ? Number(params.timeout) : undefined;
delete params.timeout;
Comment on lines +381 to +383
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleting params.timeout after extraction could cause issues if the command legitimately expects a timeout parameter. Consider using a different naming convention (e.g., --cli-timeout) to avoid conflicts.

Suggested change
// Extract --timeout from params (CLI-level override, not a command parameter)
const userTimeoutMs = params.timeout ? Number(params.timeout) : undefined;
delete params.timeout;
// Extract --timeout from params (CLI-level override)
const userTimeoutMs = params.timeout ? Number(params.timeout) : undefined;

Copilot uses AI. Check for mistakes.

// Category-based default timeouts
const isAICommand = command.startsWith('ai/');
const isGenomeCommand = command.startsWith('genome/');
const isInterfaceCommand = command.startsWith('interface/');
Expand All @@ -390,9 +391,11 @@ async function main() {
const isCollaborationCommand = command.startsWith('collaboration/');
const isChallengeCommand = command.startsWith('challenge/');
const isCodeCommand = command.startsWith('code/');
const needsLongerTimeout = isAICommand || isInferenceCommand || isSocialCommand || isInterfaceCommand || isCollaborationCommand || isCodeCommand;
const needsLongTimeout = isGenomeCommand || isChallengeCommand;
const timeoutMs = needsLongTimeout ? 300000 : needsLongerTimeout ? 60000 : 10000; // 5min for genome/challenge, 60s for AI/inference/social/interface/collaboration/code, 10s for others
const isSentinelCommand = command.startsWith('sentinel/');
const needsLongerTimeout = isAICommand || isSocialCommand || isInterfaceCommand || isCollaborationCommand || isCodeCommand;
const needsLongTimeout = isGenomeCommand || isChallengeCommand || isInferenceCommand || isSentinelCommand;
const defaultTimeoutMs = needsLongTimeout ? 300000 : needsLongerTimeout ? 60000 : 10000; // 5min for genome/challenge/inference/sentinel, 60s for AI/social/interface/collaboration/code, 10s for others
const timeoutMs = userTimeoutMs ?? defaultTimeoutMs;
const timeoutSeconds = timeoutMs / 1000;

const commandTimeout = new Promise((_, reject) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class AiAgentServerCommand extends AiAgentCommand {
const provider = params.provider || 'anthropic';
const model = params.model || (
provider === 'anthropic' ? 'claude-sonnet-4-5-20250929' :
provider === 'candle' || provider === 'ollama' ? LOCAL_MODELS.DEFAULT :
provider === 'candle' ? LOCAL_MODELS.DEFAULT :
'claude-sonnet-4-5-20250929'
);

Expand Down
2 changes: 1 addition & 1 deletion src/debug/jtag/commands/ai/agent/shared/AiAgentTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface AiAgentParams extends CommandParams {
/** Model ID (e.g., 'claude-sonnet-4-5-20250929', 'llama-3.1-8b') */
model?: string;

/** Provider (e.g., 'anthropic', 'openai', 'together', 'ollama') */
/** Provider (e.g., 'anthropic', 'openai', 'together', 'candle') */
provider?: string;

/** Sampling temperature */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,12 @@ export class AIGenerateServerCommand extends AIGenerateCommand {
params.roomId,
targetPersonaId,
{
modelId: params.model,
provider: params.provider,
maxMessages: params.maxMessages || 20,
includeArtifacts: params.includeArtifacts ?? true,
includeMemories: params.includeMemories ?? true,
triggeringTimestamp: Date.now(), // Preview shows current state (no race filtering for manual preview)
triggeringTimestamp: Date.now(),
maxTokens: params.maxTokens ?? 2000,
}
);
Expand Down
9 changes: 3 additions & 6 deletions src/debug/jtag/commands/ai/generate/shared/AIGenerateTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,11 @@ export interface AIGenerateParams extends CommandParams {
// Preview mode - returns request instead of calling LLM
preview?: boolean;

// Model configuration
model?: string;
// Model configuration — required for RAG budget and inference routing
model: string;
provider: 'openai' | 'anthropic' | 'local' | 'candle' | 'groq' | 'deepseek';
Comment on lines +38 to +39
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making model and provider required is a breaking API change. All existing callers that relied on defaults will break. Consider providing migration guidance or a compatibility layer that infers these from context when missing.

Suggested change
model: string;
provider: 'openai' | 'anthropic' | 'local' | 'candle' | 'groq' | 'deepseek';
// May be omitted by callers that rely on defaults inferred from context.
model?: string;
provider?: 'openai' | 'anthropic' | 'local' | 'candle' | 'groq' | 'deepseek';

Copilot uses AI. Check for mistakes.
temperature?: number;
maxTokens?: number;

// Provider selection
// 'local' and 'candle' route to native Rust inference (Candle)
provider?: 'openai' | 'anthropic' | 'local' | 'candle' | 'groq' | 'deepseek';
}

// AI Generate Result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export class RAGInspectServerCommand extends RAGInspectCommand {
params.contextId,
params.personaId,
{
modelId: params.modelId,
provider: params.provider,
maxMessages: params.maxMessages ?? 20,
includeArtifacts: params.includeArtifacts ?? true,
includeMemories: params.includeMemories ?? true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ export interface RAGInspectParams extends CommandParams {
/** Persona ID requesting context */
personaId: UUID;

/** Model ID — drives context window budget */
modelId: string;

/** Provider — scopes model lookup */
provider: string;

/** Optional: Limit number of messages */
maxMessages?: number;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ export class ThoughtStreamServerCommand extends ThoughtStreamCommand {
stream.contextId,
thought.personaId,
{
modelId: params.modelId,
provider: params.provider,
maxTokens: 2000,
maxMessages: 20,
maxMemories: 0,
Expand Down Expand Up @@ -394,6 +396,8 @@ export class ThoughtStreamServerCommand extends ThoughtStreamCommand {
entry.roomId,
personaId,
{
modelId: params.modelId,
provider: params.provider,
maxTokens: 2000,
maxMessages: 20,
maxMemories: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export interface ThoughtStreamParams extends CommandParams {
since?: string; // Time range (e.g., "5m", "1h")
limit?: number; // Max number of streams to show (default 10)

// Model context for RAG budget calculation
modelId: string; // Target model — drives context window budget
provider: string; // AI provider — scopes model lookup

// Display options
showContent?: boolean; // Show actual message content (not "Unknown")
showRagContext?: boolean; // Include RAG context for each thought
Expand Down
135 changes: 135 additions & 0 deletions src/debug/jtag/commands/genome/academy-competition/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Genome Academy Competition Command

Launches a multi-persona competition: 1 shared teacher sentinel generates a curriculum, N student sentinels compete on the same exam questions. Rankings computed from exam scores across all topics.

## Table of Contents

- [Usage](#usage)
- [CLI Usage](#cli-usage)
- [Tool Usage](#tool-usage)
- [Parameters](#parameters)
- [Result](#result)
- [Examples](#examples)
- [Architecture](#architecture)
- [Testing](#testing)
- [Getting Help](#getting-help)
- [Access Level](#access-level)
- [Implementation Notes](#implementation-notes)

## Usage

### CLI Usage

```bash
./jtag genome/academy-competition --skill="typescript-generics" --competitors='[{"personaId":"<uuid1>","personaName":"Helper AI"},{"personaId":"<uuid2>","personaName":"Code Tutor"}]'
```

### Tool Usage

```typescript
import { GenomeAcademyCompetition } from '@commands/genome/academy-competition/shared/GenomeAcademyCompetitionTypes';

const result = await GenomeAcademyCompetition.execute({
skill: 'typescript-generics',
competitors: [
{ personaId: '<uuid1>', personaName: 'Helper AI' },
{ personaId: '<uuid2>', personaName: 'Code Tutor' },
],
baseModel: 'smollm2:135m',
passingScore: 70,
});
```

## Parameters

- **skill** (required): `string` - Skill to compete on (e.g., "typescript-generics")
- **competitors** (required): `CompetitorDef[]` - Array of competitors (minimum 2), each with `personaId` and `personaName`
- **baseModel** (optional): `string` - Base model for training (default: "smollm2:135m")
- **maxTopicAttempts** (optional): `number` - Maximum attempts per topic before failure (default: 3)
- **passingScore** (optional): `number` - Score required to pass exams, 0-100 (default: 70)
- **epochs** (optional): `number` - Training epochs per round (default: 3)
- **rank** (optional): `number` - LoRA rank (default: 32)
- **tournamentRounds** (optional): `number` - Number of tournament rounds (default: 1)
- **model** (optional): `string` - Teacher LLM model
- **provider** (optional): `string` - Teacher LLM provider

## Result

Returns `GenomeAcademyCompetitionResult` with:

- **success**: `boolean` - Whether competition was created and sentinels spawned
- **competitionId**: `UUID` - The created competition entity ID
- **teacherHandle**: `string` - Sentinel handle for the shared teacher pipeline
- **competitorHandles**: `CompetitorHandle[]` - Per-competitor handles with `personaId`, `personaName`, `studentHandle`, `sessionId`
- **error**: `string` (optional) - Error message if failed

## Examples

### Two-persona competition

```bash
./jtag genome/academy-competition \
--skill="typescript-generics" \
--competitors='[{"personaId":"00000000-0000-0000-0000-000000000002","personaName":"Helper AI"},{"personaId":"00000000-0000-0000-0000-000000000003","personaName":"Code Tutor"}]'
```

### Track competition progress

```bash
# Check teacher
./jtag sentinel/status --handle="<teacherHandle>"

# Check each student
./jtag sentinel/status --handle="<studentHandle1>"
./jtag sentinel/status --handle="<studentHandle2>"

# View competition entity
./jtag data/read --collection="competitions" --id="<competitionId>"
```

## Architecture

Extends the Academy Dojo dual-sentinel pattern to N students:

```
1 Teacher Sentinel (shared)
|
+---> Student Sentinel 1 (persona A)
+---> Student Sentinel 2 (persona B)
+---> Student Sentinel N (persona N)
```

All students receive the same curriculum and exam questions from the shared teacher. Each trains independently. Rankings are computed from exam scores.

See `docs/personas/ACADEMY-DOJO-ARCHITECTURE.md` for full design.

## Testing

```bash
# Unit tests
npx vitest run tests/unit/semantic-cognition.test.ts

# Integration tests (requires running server + Rust sentinel engine)
npm start
npx vitest run tests/integration/sentinel-lora-training.test.ts
```

## Getting Help

```bash
./jtag help genome/academy-competition
./jtag readme genome/academy-competition
```

## Access Level

**ai-safe** - Safe for AI personas to call autonomously.

## Implementation Notes

- **Shared Logic**: `shared/GenomeAcademyCompetitionTypes.ts`
- **Browser**: `browser/GenomeAcademyCompetitionBrowserCommand.ts`
- **Server**: `server/GenomeAcademyCompetitionServerCommand.ts`
- Entities: `CompetitionEntity` (collection: `competitions`)
- Per-competitor `AcademySessionEntity` for independent training tracking
- Events share competition ID as session scope for teacher broadcasts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Genome Academy Competition Command - Browser Implementation
*
* Delegates to server for competition orchestration.
*/

import { CommandBase, type ICommandDaemon } from '@daemons/command-daemon/shared/CommandBase';
import type { JTAGContext } from '@system/core/types/JTAGTypes';
import type { GenomeAcademyCompetitionParams, GenomeAcademyCompetitionResult } from '../shared/GenomeAcademyCompetitionTypes';

export class GenomeAcademyCompetitionBrowserCommand extends CommandBase<GenomeAcademyCompetitionParams, GenomeAcademyCompetitionResult> {

constructor(context: JTAGContext, subpath: string, commander: ICommandDaemon) {
super('genome/academy-competition', context, subpath, commander);
}

async execute(params: GenomeAcademyCompetitionParams): Promise<GenomeAcademyCompetitionResult> {
console.log('🌐 BROWSER: Delegating Genome Academy Competition to server');
return await this.remoteExecute(params);
}
}
35 changes: 35 additions & 0 deletions src/debug/jtag/commands/genome/academy-competition/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "@jtag-commands/genome/academy-competition",
"version": "1.0.0",
"description": "Launch a multi-persona Academy competition — 1 teacher sentinel + N student sentinels competing on the same curriculum",
"main": "server/GenomeAcademyCompetitionServerCommand.ts",
"types": "shared/GenomeAcademyCompetitionTypes.ts",
"scripts": {
"test": "npm run test:unit && npm run test:integration",
"test:unit": "npx vitest run test/unit/*.test.ts",
"test:integration": "npx tsx test/integration/GenomeAcademyCompetitionIntegration.test.ts",
"lint": "npx eslint **/*.ts",
"typecheck": "npx tsc --noEmit"
},
"peerDependencies": {
"@jtag/core": "*"
},
"files": [
"shared/**/*.ts",
"browser/**/*.ts",
"server/**/*.ts",
"test/**/*.ts",
"README.md"
],
"keywords": [
"jtag",
"command",
"genome/academy-competition"
],
"license": "MIT",
"author": "",
"repository": {
"type": "git",
"url": ""
}
}
Loading
Loading