## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Design Philosophy

The principles and values guiding Knowledge Base 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 KB to their workflows, not vice versa.

Example:

    #![allow(unused)]
    fn main() {
    // ❌ 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

    # 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:

    # 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:

    ---
    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:

    #![allow(unused)]
    fn main() {
    // 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:

    #![allow(unused)]
    fn main() {
    // ❌ 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:

    ❌ "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:

    # 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:

- `--kb-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:

    # 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:

    "Find anything about handling errors gracefully"

KB 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:

    # 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:

    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

    #![allow(unused)]
    fn main() {
    // Don't
    const EMBEDDING_MODEL: &str = "BAAI/bge-small-en-v1.5";

    // Do
    let model = config.embeddings.model.as_str();
    }

### 2. ❌ Runtime Schema Validation

    // 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

    #![allow(unused)]
    fn main() {
    // Don't
    Err("Failed".into())

    // Do
    Err(KbError::NodeNotFound(id.to_string()))
    }

### 4. ❌ Coupling Components

    #![allow(unused)]
    fn main() {
    // 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

    // Don't
    Binary blob: [0x4B, 0x42, 0x01, ...]

    // Do
    Markdown + YAML:
    ---
    id: note-1
    ---
    # Content

## Influences

KB 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

KB 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
- Understand architecture: System Overview
- Start using: Quick Start