feat: implement CI (Continuous Intelligence) autonomous engineering harness

Implements the full PRD for CI - a fully autonomous AI-driven software
engineering harness derived from Learnship's architecture.

Core components:
- CI Orchestrator agent with autonomous pipeline (SPECIFY → CLARIFY →
  RESEARCH → PLAN → EXECUTE → VERIFY → COMPLETE)
- Decision Engine with confidence thresholds (high/medium/low)
- Clarify Phase with question budget and default acceptance
- Escalation Protocol with timeout auto-proceed
- Audit Trail system (.ci/audit/) for post-hoc review
- Error Recovery with retry, plan revision, and rollback

18 agents (all Learnship agents + Orchestrator):
- Autonomous behavioral modifications per PRD §7.1
- Agent registry with factory pattern

11 CLI commands:
- ci init, ci run, ci quick, ci debug, ci verify
- ci review, ci status, ci audit, ci clarify
- ci rollback, ci ship

4-layer verification system:
- Structural, Behavioral, Security, Code Quality

3 autonomy levels: full, supervised, guided
Compatible with Learnship artifact schemas (.planning/)
This commit is contained in:
CI
2026-05-28 23:24:42 +00:00
commit 9cf5c000d9
57 changed files with 7336 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
export interface ClarifyQuestion {
id: string;
question: string;
context: string;
default_answer: string;
rationale: string;
impact: "critical" | "high" | "medium" | "low";
category: string;
answered: boolean;
answer?: string;
agent_interpretation?: string;
}
export interface ClarifyResult {
questions: ClarifyQuestion[];
total_questions: number;
answered_questions: number;
unanswered_defaults_accepted: number;
completed_at: string;
}
export function createClarifyQuestion(
params: Omit<ClarifyQuestion, "id" | "answered">
): ClarifyQuestion {
return {
...params,
id: `Q-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
answered: false,
};
}
+105
View File
@@ -0,0 +1,105 @@
export type AutonomyLevel = "full" | "supervised" | "guided";
export type ModelProfile = "quality" | "speed" | "balanced";
export type BranchingStrategy = "phase" | "feature" | "trunk";
export type PhaseName = "research" | "plan" | "execute" | "verify" | "complete";
export type AgentName =
| "orchestrator"
| "planner"
| "executor"
| "verifier"
| "researcher"
| "phase-researcher"
| "challenger"
| "security-auditor"
| "debugger"
| "doc-writer"
| "doc-verifier"
| "code-reviewer"
| "ideation-agent"
| "roadmapper"
| "plan-checker"
| "project-researcher"
| "research-synthesizer"
| "solution-writer";
export interface AutonomyConfig {
level: AutonomyLevel;
escalation_hooks: string[];
clarify_budget: number;
decision_confidence_threshold: number;
max_revision_iterations: number;
max_verification_retries: number;
escalation_timeout_ms: number;
}
export interface ParallelizationConfig {
enabled: boolean;
max_concurrent_agents: number;
min_plans_for_parallel: number;
}
export interface VerificationConfig {
automated_only: boolean;
escalate_visual: boolean;
escalate_external_integration: boolean;
test_first: boolean;
}
export interface SecurityConfig {
auto_accept_low_severity: boolean;
auto_mitigate_medium_severity: boolean;
escalate_high_severity: boolean;
}
export interface GitConfig {
branching_strategy: BranchingStrategy;
auto_commit: boolean;
auto_push: boolean;
}
export interface CIConfig {
autonomy: AutonomyConfig;
model_profile: ModelProfile;
parallelization: ParallelizationConfig;
verification: VerificationConfig;
security: SecurityConfig;
git: GitConfig;
}
export const DEFAULT_CI_CONFIG: CIConfig = {
autonomy: {
level: "full",
escalation_hooks: ["deploy", "delete_data", "merge_to_main"],
clarify_budget: 10,
decision_confidence_threshold: 0.6,
max_revision_iterations: 3,
max_verification_retries: 2,
escalation_timeout_ms: 300000,
},
model_profile: "quality",
parallelization: {
enabled: true,
max_concurrent_agents: 5,
min_plans_for_parallel: 2,
},
verification: {
automated_only: true,
escalate_visual: true,
escalate_external_integration: true,
test_first: false,
},
security: {
auto_accept_low_severity: true,
auto_mitigate_medium_severity: true,
escalate_high_severity: true,
},
git: {
branching_strategy: "phase",
auto_commit: true,
auto_push: false,
},
};
+43
View File
@@ -0,0 +1,43 @@
export type ConfidenceLevel = "high" | "medium" | "low";
export type DecisionCategory =
| "implementation_approach"
| "technology_choice"
| "architecture"
| "scope"
| "verification"
| "security"
| "deployment"
| "general";
export interface Decision {
id: string;
timestamp: string;
decision: string;
rationale: string;
confidence: number;
category: DecisionCategory;
alternatives_considered: Alternative[];
learnship_equivalent: string;
human_override: string | null;
phase?: string;
task?: string;
}
export interface Alternative {
option: string;
rejected_reason: string;
}
export function confidenceToLevel(confidence: number): ConfidenceLevel {
if (confidence > 0.85) return "high";
if (confidence >= 0.6) return "medium";
return "low";
}
export function shouldEscalate(
confidence: number,
threshold: number
): boolean {
return confidence < threshold;
}
+51
View File
@@ -0,0 +1,51 @@
export type EscalationType =
| "irreversible_action"
| "verification_failure"
| "low_confidence_decision"
| "security_escalation"
| "specification_ambiguity";
export type EscalationResolution =
| "approved"
| "rejected"
| "modified"
| "pending"
| "timeout_auto_proceed";
export interface EscalationOption {
id: string;
label: string;
description: string;
recommended: boolean;
}
export interface Escalation {
id: string;
timestamp: string;
type: EscalationType;
phase: string;
plan?: string;
task?: string;
description: string;
context: string;
options: EscalationOption[];
default_option_id: string;
resolution: EscalationResolution;
resolved_at?: string;
resolution_detail?: string;
audit_file: string;
}
export interface EscalationResult {
escalation: Escalation;
chosen_option_id: string;
timestamp: string;
}
export const ESCALATION_TYPES: Record<EscalationType, string> = {
irreversible_action: "Irreversible Action",
verification_failure: "Verification Failure",
low_confidence_decision: "Low Confidence Decision",
security_escalation: "Security Escalation",
specification_ambiguity: "Specification Ambiguity",
};
+6
View File
@@ -0,0 +1,6 @@
export * from "./config.js";
export * from "./decisions.js";
export * from "./escalation.js";
export * from "./pipeline.js";
export * from "./clarify.js";
export * from "./specification.js";
+92
View File
@@ -0,0 +1,92 @@
import { AgentName, PhaseName } from "./config.js";
export type PipelineStage =
| "specify"
| "clarify"
| "research"
| "plan"
| "execute"
| "verify"
| "complete";
export interface PipelineState {
project_path: string;
current_stage: PipelineStage;
current_phase: number;
phases_completed: number[];
specification_loaded: boolean;
clarify_completed: boolean;
research_completed: boolean;
plan_completed: boolean;
execute_completed: boolean;
verify_completed: boolean;
errors: PipelineError[];
started_at: string;
last_updated: string;
}
export interface PipelineError {
stage: PipelineStage;
phase: number;
message: string;
timestamp: string;
retry_count: number;
resolved: boolean;
}
export interface PhaseResult {
phase: number;
stage: PipelineStage;
success: boolean;
artifacts_created: string[];
decisions_made: number;
escalations_raised: number;
duration_ms: number;
error?: string;
}
export interface OrchestratorResult {
success: boolean;
pipeline_state: PipelineState;
phase_results: PhaseResult[];
total_decisions: number;
total_escalations: number;
total_duration_ms: number;
completion_report: string;
}
export const STAGE_ORDER: PipelineStage[] = [
"specify",
"clarify",
"research",
"plan",
"execute",
"verify",
"complete",
];
export function getNextStage(current: PipelineStage): PipelineStage | null {
const idx = STAGE_ORDER.indexOf(current);
if (idx < 0 || idx >= STAGE_ORDER.length - 1) return null;
return STAGE_ORDER[idx + 1];
}
export function createInitialPipelineState(
project_path: string
): PipelineState {
return {
project_path,
current_stage: "specify",
current_phase: 0,
phases_completed: [],
specification_loaded: false,
clarify_completed: false,
research_completed: false,
plan_completed: false,
execute_completed: false,
verify_completed: false,
errors: [],
started_at: new Date().toISOString(),
last_updated: new Date().toISOString(),
};
}
+58
View File
@@ -0,0 +1,58 @@
export interface Specification {
title: string;
objective: string;
requirements: string[];
constraints: string[];
out_of_scope: string[];
raw_content: string;
source: "inline" | "file" | "clarify";
created_at: string;
}
export function parseSpecification(content: string, source: "inline" | "file" | "clarify" = "inline"): Specification {
const lines = content.split("\n");
let title = "";
let objective = "";
const requirements: string[] = [];
const constraints: string[] = [];
const outOfScope: string[] = [];
let currentSection: "objective" | "requirements" | "constraints" | "out_of_scope" | null = null;
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith("# ")) {
if (!title) title = trimmed.slice(2);
} else if (trimmed.startsWith("## Objective")) {
currentSection = "objective";
} else if (trimmed.startsWith("## Requirements")) {
currentSection = "requirements";
} else if (trimmed.startsWith("## Constraints")) {
currentSection = "constraints";
} else if (trimmed.startsWith("## Out of Scope")) {
currentSection = "out_of_scope";
} else if (trimmed.startsWith("- ") && currentSection) {
const item = trimmed.slice(2);
if (currentSection === "objective") objective = (objective ? objective + " " : "") + item;
else if (currentSection === "requirements") requirements.push(item);
else if (currentSection === "constraints") constraints.push(item);
else if (currentSection === "out_of_scope") outOfScope.push(item);
} else if (trimmed && currentSection === "objective") {
objective = (objective ? objective + " " : "") + trimmed;
}
}
if (!title) title = "Untitled Project";
if (!objective) objective = content.slice(0, 200);
return {
title,
objective,
requirements,
constraints,
out_of_scope: outOfScope,
raw_content: content,
source,
created_at: new Date().toISOString(),
};
}