Initial scaffold: GyanDoot v2.0 in Rust

Full Cargo workspace with 11 crates:
- gyandoot-core: Shared types, config, error types
- gyandoot-agent: Agent loop, tool execution, context compression
- gyandoot-providers: LLM provider abstraction (OpenAI, Anthropic, Ollama)
- gyandoot-memory: MemPalace persistent memory system
- gyandoot-platform: Platform adapters (Telegram, Discord, Webhook, CLI)
- gyandoot-security: Credential vault, sanitizer, threat detector
- gyandoot-kanban: Task decomposition, swarm orchestration, diagnostics
- gyandoot-subagents: Sub-agent spawning and orchestration
- gyandoot-skills: Skills discovery, loading, preprocessing, bundles
- gyandoot-profile: Multi-agent profile manager
- gyandoot-gateway: Gateway sessions, routing, access control

Plus: CLI entry point with clap, cross-platform installer script,
KANBAN.md, .gnpl/AGENTS.md

Workspace compiles clean: cargo check passes with 0 errors.
This commit is contained in:
2026-06-11 20:04:12 +05:30
commit 851c838ca5
53 changed files with 8037 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
[package]
name = "gyandoot-profile"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "GyanDoot v2 — Multi-agent profile manager"
[dependencies]
gyandoot-core = { path = "../gyandoot-core" }
tokio.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
anyhow.workspace = true
tracing.workspace = true
uuid.workspace = true
dirs.workspace = true

View File

@@ -0,0 +1,120 @@
//! # Gyandoot Profile Manager
//!
//! Multi-agent profile management. Each profile is a self-contained config.yaml
//! with its own model, provider, and platform settings.
use std::collections::HashMap;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
/// A named agent profile with self-contained configuration.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Profile {
pub name: String,
pub model: String,
pub provider: String,
pub base_url: Option<String>,
pub api_key: Option<String>,
pub temperature: Option<f64>,
pub max_tokens: Option<u32>,
pub gateway: Option<GatewaySettings>,
}
/// Gateway settings scoped to a profile.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GatewaySettings {
pub enabled: bool,
pub platforms: HashMap<String, PlatformBinding>,
}
/// Platform binding within a profile.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlatformBinding {
pub token: Option<String>,
pub home_channel: Option<String>,
pub allowed_users: Option<Vec<String>>,
pub allowed_channels: Option<Vec<String>>,
}
impl Profile {
pub fn new(name: &str, model: &str, provider: &str) -> Self {
Self {
name: name.to_string(),
model: model.to_string(),
provider: provider.to_string(),
base_url: None,
api_key: None,
temperature: None,
max_tokens: None,
gateway: None,
}
}
}
/// Resolves configuration from profile marker -> file -> defaults.
pub struct ConfigResolver {
gyandoot_home: PathBuf,
}
impl ConfigResolver {
pub fn new() -> Self {
let home = dirs::home_dir().unwrap_or_default();
Self {
gyandoot_home: home.join(".gyandoot"),
}
}
pub fn profiles_dir(&self) -> PathBuf {
self.gyandoot_home.join("profiles")
}
pub fn active_profile_path(&self) -> PathBuf {
self.gyandoot_home.join("active_profile")
}
pub fn profile_config_path(&self, name: &str) -> PathBuf {
self.profiles_dir().join(name).join("config.yaml")
}
pub fn default_config_path(&self) -> PathBuf {
self.gyandoot_home.join("config.yaml")
}
pub fn resolve(&self) -> ResolvedConfig {
ResolvedConfig {
gyandoot_home: self.gyandoot_home.clone(),
profile_name: "default".to_string(),
}
}
}
impl Default for ConfigResolver {
fn default() -> Self {
Self::new()
}
}
/// Resolved configuration metadata.
pub struct ResolvedConfig {
pub gyandoot_home: PathBuf,
pub profile_name: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_profile_creation() {
let p = Profile::new("dev", "claude-sonnet-4", "anthropic");
assert_eq!(p.name, "dev");
assert_eq!(p.model, "claude-sonnet-4");
}
#[test]
fn test_config_resolver_paths() {
let resolver = ConfigResolver::new();
assert!(resolver.gyandoot_home.to_string_lossy().contains(".gyandoot"));
assert!(resolver.profiles_dir().to_string_lossy().contains("profiles"));
}
}