use std::path::Path;
use anyhow::Result;
use clap::{Parser, Subcommand};
use polar_bear_biochip::{
agent::BioChipAgent,
provenance::{EcdsaSigner, EcdsaVerifier},
sensors::SensorFusion,
types::SignedOutput,
};
use sha2::Digest;
use tracing::{info, warn};
#[derive(Parser)]
#[command(
name = "polar-bear-biochip",
version,
about = "Bio-chip intelligence: sensor fusion → rig-core LLM → ECDSA provenance",
long_about = "Fuses EEG + accelerometer data, infers cognitive state via a rig-core LLM\n\
agent, and ECDSA-signs every output for blockchain-grade provenance.\n\
All operations run in DRY-RUN / DEMO mode by default (no API key needed)."
)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand)]
enum Commands {
Run {
#[arg(short, long, default_value_t = 5)]
cycles: u32,
#[arg(short, long)]
demo: bool,
#[arg(short, long, default_value = "signed_outputs")]
output_dir: std::path::PathBuf,
#[arg(short, long, default_value = "claude-sonnet-4-6")]
model: String,
},
Verify {
file: std::path::PathBuf,
},
}
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive("polar_bear_biochip=info".parse()?),
)
.init();
let cli = Cli::parse();
match cli.command.unwrap_or(Commands::Run {
cycles: 5,
demo: false,
output_dir: "signed_outputs".into(),
model: "claude-sonnet-4-6".to_string(),
}) {
Commands::Run {
cycles,
demo,
output_dir,
model,
} => cmd_run(cycles, demo, &output_dir, &model).await,
Commands::Verify { file } => cmd_verify(&file),
}
}
async fn cmd_run(cycles: u32, demo: bool, output_dir: &Path, model: &str) -> Result<()> {
println!();
println!(" ╔═══════════════════════════════════════════════════╗");
println!(" ║ Polar Bear · Bio-Chip Intelligence Framework ║");
println!(" ║ Sensor Fusion · rig-core · ECDSA Provenance ║");
println!(" ╚═══════════════════════════════════════════════════╝");
println!();
let demo = demo || std::env::var("ANTHROPIC_API_KEY").is_err();
if demo {
warn!("ANTHROPIC_API_KEY not found or --demo set → running in demo mode.");
info!("Set ANTHROPIC_API_KEY and remove --demo for live rig-core inference.");
info!("Or build with: cargo build --features ai-agent");
} else {
info!("Live inference mode [model={model}]");
}
info!("Generating ECDSA keypair (secp256k1)...");
let signer = EcdsaSigner::generate();
info!(
"Public Key : {}...{}",
&signer.public_key_hex()[..12],
&signer.public_key_hex()[118..],
);
info!("Initialising sensor fusion (BCI + Accelerometer)...");
let mut fusion = SensorFusion::new();
info!("Initialising rig-core LLM agent [model={model}]...");
let agent = BioChipAgent::new(model, demo);
std::fs::create_dir_all(output_dir)?;
let total = if cycles == 0 { u32::MAX } else { cycles };
for cycle in 1..=total {
run_cycle(cycle, total, &mut fusion, &agent, &signer, output_dir).await?;
if cycle < total {
tokio::time::sleep(tokio::time::Duration::from_millis(400)).await;
}
}
println!();
println!(" ══════════════════════════════════════════════════════");
println!(" {total} cycle(s) complete.");
println!(" Signed outputs written to: {}/", output_dir.display());
println!();
println!(" Verify offline:");
println!(
" cargo run -- verify {}/cycle_001.json",
output_dir.display()
);
println!(" ══════════════════════════════════════════════════════");
Ok(())
}
#[allow(clippy::similar_names)]
async fn run_cycle(
cycle: u32,
total: u32,
fusion: &mut SensorFusion,
agent: &BioChipAgent,
signer: &EcdsaSigner,
output_dir: &Path,
) -> Result<()> {
println!();
println!(" ──────────────────────────────────────────────────────");
println!(
" CYCLE {:03}/{total:03} | {}",
cycle,
chrono::Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ"),
);
println!(" ──────────────────────────────────────────────────────");
let fused = fusion.sample(u64::from(cycle));
println!(
" [SENSORS] BCI α={:.1} β={:.1} θ={:.1} δ={:.1} γ={:.1} Hz",
fused.bci.alpha_hz,
fused.bci.beta_hz,
fused.bci.theta_hz,
fused.bci.delta_hz,
fused.bci.gamma_hz,
);
println!(
" [SENSORS] Accel x={:+.2} y={:+.2} z={:.2} m/s² | {:?}",
fused.accelerometer.x,
fused.accelerometer.y,
fused.accelerometer.z,
fused.accelerometer.activity_state,
);
println!(
" [SENSORS] Fused cogLoad={:.2} valence={:+.2} arousal={:.2} attn={:.2}",
fused.cognitive_load,
fused.emotional_valence,
fused.arousal_level,
fused.bci.attention_index,
);
println!(" [AGENT] Querying rig-core LLM agent...");
let result = agent.infer(fused).await?;
println!(" [RESULT] Alert : {}", result.alert_level);
println!(" [RESULT] Cognitive State: {}", result.cognitive_state);
println!(" [RESULT] Recommendations:");
for rec in &result.recommendations {
println!(" • {rec}");
}
let signed = signer.sign_result(&result)?;
println!(
" [PROV] Hash : {}...",
&signed.payload_hash_hex[..20]
);
println!(" [PROV] Signature : {}...", &signed.signature_hex[..20]);
let verifier = EcdsaVerifier::from_hex(&signed.public_key_hex)?;
let hash = sha2::Digest::finalize(sha2::Sha256::new_with_prefix(
serde_json::to_string(&signed.inference_result)?.as_bytes(),
));
if verifier.verify(&hash, &signed.signature_hex)? {
println!(" [PROV] ✓ ECDSA signature verified inline (secp256k1 / SHA-256)");
} else {
println!(" [PROV] ✗ ECDSA verification FAILED - investigate immediately");
}
let out_path = output_dir.join(format!("cycle_{cycle:03}.json"));
std::fs::write(&out_path, serde_json::to_string_pretty(&signed)?)?;
println!(" [PROV] ✓ Signed output → {}", out_path.display());
Ok(())
}
fn cmd_verify(path: &Path) -> Result<()> {
println!();
println!(" Verifying: {}", path.display());
println!();
let json = std::fs::read_to_string(path)
.map_err(|e| anyhow::anyhow!("cannot read {}: {e}", path.display()))?;
let signed: SignedOutput = serde_json::from_str(&json)
.map_err(|e| anyhow::anyhow!("invalid JSON in {}: {e}", path.display()))?;
let valid = EcdsaSigner::verify_signed(&signed)?;
if valid {
println!(" ✅ ECDSA signature VALID");
println!();
println!(" Sequence ID : {}", signed.inference_result.sequence_id);
println!(" Signed at : {}", signed.signed_at);
println!(
" Cognitive : {}",
signed.inference_result.cognitive_state
);
println!(" Alert level : {}", signed.inference_result.alert_level);
println!(
" Public Key : {}...{}",
&signed.public_key_hex[..12],
&signed.public_key_hex[118..]
);
println!(" Payload Hash : {}...", &signed.payload_hash_hex[..20]);
println!(" Signature : {}...", &signed.signature_hex[..20]);
} else {
eprintln!(" ❌ ECDSA signature INVALID - output may have been tampered");
std::process::exit(1);
}
Ok(())
}