Initial CodeCraft: web-based coding harness for AI models

Rust backend (axum/tokio): agent loop with streaming, tools (fs, bash,
web_fetch, todo, ask_user, subagents, skills, craft snapshots/compare),
permissions with modes and rules, Anthropic + OpenAI-compatible providers,
MCP client (stdio/HTTP, elicitation), SQLite sessions, usage statistics,
compaction, commented TOML config editable via toml_edit.

React PWA: chat with live streaming, permission/question cards, modes
(build/plan/craft), settings for providers/models/prices/MCP/permissions,
raw config editor, statistics dashboard, i18n (en/de). Docker setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-08 14:39:24 +01:00
commit f3a2fe3816
62 files changed
+21835

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
//! CodeCraft – web-based coding harness for AI models.
mod api;
mod app;
mod config;
mod mcp;
mod permission;
mod prompts;
mod provider;
mod runner;
mod store;
mod tools;
mod types;
use anyhow::Result;
use tracing_subscriber::EnvFilter;
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info,codecraft=info")))
.init();
// In Docker, HOME lives on the data volume; make sure it exists for git/npm.
if let Ok(home) = std::env::var("HOME") {
let _ = std::fs::create_dir_all(home);
}
let path = config::config_path();
let (cfg, _) = config::load_or_init(&path)?;
tracing::info!("config: {}", path.display());
tracing::info!("workspace: {}", cfg.workspace().display());
if cfg.auth_token().is_empty() {
tracing::warn!("auth_token is empty – the API is unprotected. Only use this on localhost.");
}
let bind = cfg.server.bind.clone();
let app = app::App::new(path, cfg).await?;
let router = api::router(app);
let listener = tokio::net::TcpListener::bind(&bind).await?;
tracing::info!("listening on http://{bind}");
axum::serve(listener, router).with_graceful_shutdown(shutdown()).await?;
Ok(())
}
async fn shutdown() {
let _ = tokio::signal::ctrl_c().await;
tracing::info!("shutting down");
}