kogral/docs/kogral/design-philosophy.md
2026-01-23 16:11:07 +00:00

471 lines
11 KiB
Markdown

# Design Philosophy
The principles and values guiding KOGRAL design and implementation.
## Core Tenets
### 1. Config-Driven, Not Hardcoded
**Principle**: All behavior should be configurable via schemas, not baked into code.
**Why**: Flexibility without code changes. Users adapt KOGRAL to their workflows, not vice versa.
**Example**:
```rust
// ❌ Bad: Hardcoded
impl EmbeddingProvider {
fn new() -> Self {
FastEmbedProvider::new("BAAI/bge-small-en-v1.5") // Can't change
}
}
// ✅ Good: Config-driven
impl EmbeddingProvider {
fn from_config(config: &EmbeddingConfig) -> Result<Box<dyn EmbeddingProvider>> {
match config.provider {
'fastembed => Ok(Box::new(FastEmbedProvider::new(&config.model)?)),
'openai => Ok(Box::new(OpenAIProvider::new(&config.model)?)),
}
}
}
```
**Benefits**:
- Switch embedding providers without recompilation
- Different configs for dev/prod
- User choice, not developer mandate
### 2. Type-Safe Configuration
**Principle**: Validate configuration before runtime, not during.
**Why**: Catch errors early, reduce runtime failures.
**Implementation**: Nickel contracts + serde validation = double validation
```nickel
# Schema defines valid values
EmbeddingProvider = [| 'openai, 'claude, 'fastembed |]
# Typo caught at export time, not runtime
{ provider = 'opena1 } # Error: Invalid variant
```
**Benefits**:
- Errors found during `nickel export`, not during execution
- Self-documenting: schema is the spec
- Refactoring safe: change schema, find all usages
### 3. Local-First, Cloud-Optional
**Principle**: Core functionality works offline, cloud is enhancement.
**Why**: Privacy, cost control, offline development.
**Examples**:
| Feature | Local | Cloud |
| --------- | ------- | ------- |
| Storage | Filesystem | SurrealDB |
| Embeddings | fastembed | OpenAI/Claude |
| Search | Text-based | Semantic |
**Benefits**:
- Works on planes, trains, areas with poor internet
- No API costs for small projects
- Privacy-sensitive projects keep data local
- Production can use cloud for scale
### 4. Git-Friendly by Default
**Principle**: Knowledge should version alongside code.
**Why**: Knowledge describes code, should evolve with it.
**Implementation**:
- Markdown + YAML frontmatter (text-based, diffable)
- One file per node (granular commits)
- Wikilinks preserved (works in Logseq, Obsidian)
**Benefits**:
```bash
# Review knowledge changes in PRs
git diff .kogral/decisions/
# Knowledge follows branches
git checkout feature-x
# .kogral/ reflects feature-x decisions
# Knowledge merges
git merge feature-x
# Merge conflicts = knowledge conflicts (resolve intentionally)
```
### 5. AI-Native, Human-Readable
**Principle**: Optimized for AI consumption, readable by humans.
**Why**: Best of both worlds - AI-assisted discovery, human verification.
**Implementation**:
- **Structured**: YAML frontmatter for AI parsing
- **Semantic**: Embeddings for AI queries
- **Readable**: Markdown for human consumption
- **Linked**: Typed relationships for AI traversal
**Example**:
```markdown
---
id: note-auth
type: note
title: Authentication Implementation
tags: [security, auth]
relates_to: [guideline-security, pattern-jwt]
---
# Authentication Implementation
Humans read this markdown normally.
AI can:
- Parse frontmatter for metadata
- Extract tags for filtering
- Follow relates_to links
- Generate embeddings for semantic search
```
### 6. Composition Over Inheritance
**Principle**: Build systems by composing small, focused components.
**Why**: Flexibility, testability, maintainability.
**Implementation**:
```rust
// Small, focused traits
trait Storage { ... }
trait EmbeddingProvider { ... }
trait TemplateEngine { ... }
// Compose into systems
struct KnowledgeBase {
storage: Box<dyn Storage>,
embeddings: Option<Box<dyn EmbeddingProvider>>,
templates: TemplateEngine,
}
```
**Benefits**:
- Swap storage without affecting embeddings
- Disable embeddings without breaking storage
- Test components in isolation
- Add new providers by implementing trait
### 7. Fail Fast, Fail Clearly
**Principle**: Detect errors early, provide clear messages.
**Why**: Developer experience - fast feedback, actionable errors.
**Implementation**:
```rust
// ❌ Bad: Silent failure
fn load_config(path: &Path) -> Option<Config> {
std::fs::read_to_string(path)
.ok()
.and_then(|s| serde_json::from_str(&s).ok())
}
// ✅ Good: Explicit errors
fn load_config(path: &Path) -> Result<Config, ConfigError> {
let content = std::fs::read_to_string(path)
.map_err(|e| ConfigError::ReadFailed(path.to_path_buf(), e))?;
serde_json::from_str(&content)
.map_err(|e| ConfigError::ParseFailed(path.to_path_buf(), e))
}
```
**Error messages**:
```text
❌ "Failed to load config"
✅ "Failed to read config file '/path/to/config.ncl': Permission denied"
```
### 8. Convention Over Configuration (With Escape Hatches)
**Principle**: Sane defaults, but everything customizable.
**Why**: Easy to start, flexible as you grow.
**Examples**:
```nickel
# Minimal config (uses conventions)
{ graph = { name = "my-project" } }
# Defaults: filesystem storage, no embeddings, standard templates
# Full config (explicit everything)
{
graph = { name = "my-project" },
storage = { primary = 'surrealdb, /* ... */ },
embeddings = { provider = 'openai, /* ... */ },
templates = { templates_dir = "custom" },
}
```
**Conventions**:
- `.kogral/` directory in project root
- Filesystem storage by default
- YAML frontmatter + markdown body
- Standard template names (note.md.tera, decision.md.tera)
**Escape hatches**:
- `--kogral-dir` to use different location
- Configure alternative storage backends
- Custom frontmatter schemas
- Override any template
### 9. Documentation as Code
**Principle**: Documentation lives with code, versioned together.
**Why**: Outdated docs are worse than no docs.
**Implementation**:
- ADRs in `.kogral/decisions/` (alongside code)
- Guidelines in `.kogral/guidelines/` (versioned with code)
- Patterns in `.kogral/patterns/` (evolve with implementations)
**Benefits**:
```bash
# Code and docs branch together
git checkout old-version
# .kogral/ reflects that version's decisions
# Code and docs merge together
git merge feature
# Merge includes new patterns, updated guidelines
# Code and docs reviewed together
# PR shows code + decision + guideline updates
```
### 10. Optimize for Discoverability
**Principle**: Knowledge is useless if you can't find it.
**Why**: The point is to **use** knowledge, not just store it.
**Features**:
- **Text search**: Find exact keywords
- **Semantic search**: Find related concepts
- **Graph traversal**: Follow relationships
- **Tag filtering**: Narrow by category
- **MCP integration**: AI-assisted discovery
**Example**:
User doesn't remember exact term, but knows the concept:
```text
"Find anything about handling errors gracefully"
```
KOGRAL finds (semantically):
- "Error Handling with thiserror" (pattern)
- "Result Type Best Practices" (guideline)
- "Panic Recovery" (note)
- "Graceful Degradation" (pattern)
No exact keyword match needed, concept match sufficient.
### 11. Build for Humans, Enable AI
**Principle**: Humans are the primary users, AI is the assistant.
**Why**: AI should enhance human workflows, not replace them.
**Implementation**:
- **Human-readable formats**: Markdown, YAML
- **Human-editable**: Any text editor works
- **Human-discoverable**: `ls .kogral/notes/` shows files
- **AI-enhanced**: MCP for AI-assisted queries
**Example**:
```bash
# Human workflow
vim .kogral/notes/my-note.md # Edit directly
git add .kogral/notes/my-note.md
git commit -m "Add note about X"
# AI-enhanced workflow
# (in Claude Code)
"Add a note about X with tags Y, Z"
# AI creates file, human reviews
```
### 12. Embrace the Graph
**Principle**: Knowledge is interconnected, embrace the relationships.
**Why**: Context comes from connections, not isolation.
**Implementation**:
- Typed relationships (not just "related")
- Bidirectional traversal
- Relationship strength (0.0-1.0)
- Multi-hop queries
**Example**:
```text
Find all patterns that:
- Are implemented by current project
- Depend on shared guidelines
- Were added in the last 6 months
# Graph query, not sequential file search
```
## Anti-Patterns to Avoid
### 1. ❌ Hardcoding Behavior
```rust
// Don't
const EMBEDDING_MODEL: &str = "BAAI/bge-small-en-v1.5";
// Do
let model = config.embeddings.model.as_str();
```
### 2. ❌ Runtime Schema Validation
```nickel
// Don't validate at runtime
let provider = config.provider; // Might be invalid
// Do validate at export time (Nickel contracts)
provider | [| 'openai, 'claude, 'fastembed |]
```
### 3. ❌ Opaque Errors
```rust
// Don't
Err("Failed".into())
// Do
Err(KbError::NodeNotFound(id.to_string()))
```
### 4. ❌ Coupling Components
```rust
// Don't
impl KnowledgeBase {
fn search(&self) -> Vec<Node> {
let embeddings = FastEmbedProvider::new(); // Hardcoded!
// ...
}
}
// Do
impl KnowledgeBase {
fn search(&self) -> Vec<Node> {
if let Some(provider) = &self.embeddings {
// Use configured provider
}
}
}
```
### 5. ❌ Proprietary Formats
```text
// Don't
Binary blob: [0x4B, 0x42, 0x01, ...]
// Do
Markdown + YAML:
---
id: note-1
---
# Content
```
## Influences
KOGRAL draws inspiration from:
- **Logseq**: Outliner, graph view, wikilinks
- **Obsidian**: Markdown-first, local storage, plugins
- **Zettelkasten**: Atomic notes, links, emergence
- **ADR**: Decision records, context preservation
- **Git**: Version control, branching, merging
- **Nickel**: Type-safe configuration, contracts
- **MCP**: AI integration protocol
- **SurrealDB**: Graph database, relationships
## Implementation Principles
### Rust
- Zero unsafe code (`#![forbid(unsafe_code)]`)
- No `unwrap()` in production code
- Always use `Result<T>` for fallibility
- Comprehensive error types with `thiserror`
- Full test coverage (100+ tests)
### Nickel
- Contracts for validation
- Defaults in schemas
- Documentation in contracts
- Composition via imports
### NuShell
- Structured data pipelines
- Error handling in scripts
- Colored output for UX
- Dry-run modes
## Evolution Strategy
KOGRAL follows these guidelines for evolution:
1. **Backward Compatibility**: Don't break existing configs
2. **Deprecation Period**: Warn before removal (1 major version)
3. **Migration Tools**: Provide automated migrations
4. **Semantic Versioning**: MAJOR.MINOR.PATCH strictly
## Conclusion
These principles guide every decision:
**Config-driven**: Behavior in schemas, not code
**Type-safe**: Validate before runtime
**Local-first**: Works offline, cloud optional
**Git-friendly**: Knowledge versions with code
**AI-native**: Optimized for AI, readable by humans
**Composable**: Small pieces, loosely coupled
**Fast feedback**: Fail early, clear errors
**Discoverable**: Easy to find what you need
The goal: **Knowledge management that developers actually use.**
## Next Steps
- **See it in action**: [Use Cases](../guides/use-cases.md)
- **Understand architecture**: [System Overview](../architecture/overview.md)
- **Start using**: [Quick Start](../guides/quickstart.md)