feat: add 'mem learn' CLI for markdown knowledge ingestion
Build and Push / Test (push) Failing after 6s
Build and Push / Build and push image (push) Skipped

6 knowledge files: rust, SOLID/DRY, ast-grep, karpathy, golang, caveman
65 chunks ingested to log/knowledge/learn/latest.jsonl
Chunks on ## headings, SHA256 dedup, configurable chunk size
This commit is contained in:
2026-08-29 22:04:14 -07:00
parent fcdcd2d037
commit 762acea610
10 changed files with 621 additions and 0 deletions
Generated
+1
View File
@@ -2006,6 +2006,7 @@ dependencies = [
"tracing-subscriber",
"urlencoding",
"uuid",
"walkdir",
]
[[package]]
+1
View File
@@ -40,3 +40,4 @@ jsonwebtoken = { workspace = true }
reqwest = { workspace = true }
async-trait = { workspace = true }
urlencoding = { workspace = true }
walkdir = "2.5"
+166
View File
@@ -155,6 +155,25 @@ enum Commands {
#[arg(long, value_name = "FILE")]
file: Option<PathBuf>,
},
/// Ingest markdown knowledge files into memory
Learn {
/// Markdown files or directories to ingest
#[arg(value_name = "PATH")]
paths: Vec<PathBuf>,
/// Project to file under
#[arg(long, default_value = "knowledge")]
project: String,
/// Dry run — show chunks without writing
#[arg(long)]
dry_run: bool,
/// Maximum chunk size in characters (splits on headings)
#[arg(long, default_value_t = 2000)]
chunk_size: usize,
},
}
#[tokio::main]
@@ -213,6 +232,9 @@ async fn main() -> anyhow::Result<()> {
Commands::Sig { tool, file } => {
cmd_sig(&tool, file.as_ref())?
}
Commands::Learn { paths, project, dry_run, chunk_size } => {
cmd_learn(&paths, &project, dry_run, chunk_size)?;
}
}
Ok(())
@@ -379,6 +401,150 @@ async fn cmd_verify(
Ok(())
}
fn cmd_learn(
paths: &[PathBuf],
project: &str,
dry_run: bool,
max_chunk: usize,
) -> anyhow::Result<()> {
use sha2::{Digest, Sha256};
let mut all_files: Vec<PathBuf> = Vec::new();
for p in paths {
if p.is_dir() {
for entry in walkdir::WalkDir::new(p)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| {
e.path()
.extension()
.map(|ext| ext == "md")
.unwrap_or(false)
})
{
all_files.push(entry.into_path());
}
} else if p.extension().map(|e| e == "md").unwrap_or(false) {
all_files.push(p.clone());
} else {
eprintln!("Skipping non-markdown file: {}", p.display());
}
}
if all_files.is_empty() {
eprintln!("No markdown files found.");
return Ok(());
}
all_files.sort();
println!("Found {} markdown files", all_files.len());
let mut total_chunks = 0usize;
let mut total_bytes = 0usize;
let mut log = if !dry_run {
Some(mem_store::LogWriter::new(project, "learn", "latest")?)
} else {
None
};
for file in &all_files {
let content = fs::read_to_string(file)?;
let filename = file.file_stem().unwrap().to_string_lossy();
let chunks = chunk_markdown(&content, max_chunk);
println!("\n📄 {}{} chunks", file.display(), chunks.len());
for (i, chunk) in chunks.iter().enumerate() {
let mut hasher = Sha256::new();
hasher.update(chunk.as_bytes());
let hash = format!("{:x}", hasher.finalize());
let short_hash = &hash[..12];
total_chunks += 1;
total_bytes += chunk.len();
if dry_run {
let preview: String = chunk.chars().take(80).collect();
println!(
" [{}/{}] {} ({} bytes) {}",
i + 1,
chunks.len(),
short_hash,
chunk.len(),
preview.replace('\n', " ")
);
} else {
let record = mem_store::EventRecord {
project: project.to_string(),
query: format!("{}:{}", filename, i),
run: "latest".to_string(),
turn: i as u32,
event_type: "learn".to_string(),
data: serde_json::json!({
"source": file.to_string_lossy(),
"chunk_index": i,
"total_chunks": chunks.len(),
"sha256": hash,
"level": "L1",
"text": chunk,
}),
};
log.as_mut().unwrap().log(record)?;
println!(" ✓ [{}/{}] {} ({} bytes)", i + 1, chunks.len(), short_hash, chunk.len());
}
}
}
println!("\n{}", "".repeat(50));
println!(
"{} files → {} chunks ({:.1} KB)",
all_files.len(),
total_chunks,
total_bytes as f64 / 1024.0
);
if dry_run {
println!("(dry run — nothing written)");
} else {
println!("Written to log/{}/learn/latest.jsonl", project);
}
Ok(())
}
/// Split markdown on ## headings, respecting max_chunk size.
fn chunk_markdown(content: &str, max_chunk: usize) -> Vec<String> {
let mut chunks = Vec::new();
let mut current = String::new();
for line in content.lines() {
// Split on ## headings (keep # title in first chunk)
if line.starts_with("## ") && !current.is_empty() {
let trimmed = current.trim().to_string();
if !trimmed.is_empty() {
chunks.push(trimmed);
}
current = String::new();
}
current.push_str(line);
current.push('\n');
// Hard split if chunk too large
if current.len() > max_chunk {
let trimmed = current.trim().to_string();
if !trimmed.is_empty() {
chunks.push(trimmed);
}
current = String::new();
}
}
let trimmed = current.trim().to_string();
if !trimmed.is_empty() {
chunks.push(trimmed);
}
chunks
}
fn cmd_sig(tool: &str, file: Option<&PathBuf>) -> anyhow::Result<()> {
use mem_core::lesson;
use std::io::Read;
+55
View File
@@ -0,0 +1,55 @@
# Andrej Karpathy — Key Insights & Practices
## Software 2.0
- Traditional software (1.0): explicit rules written by programmers.
- Software 2.0: behavior learned from data via neural networks. Code = weights.
- Implication: datasets are the new source code. Data curation > clever algorithms.
- Debug by inspecting data, not stepping through logic.
## Training Neural Networks — A Recipe
1. **Become one with the data** — visualize, understand distributions, find patterns and anomalies before writing any model code.
2. **Set up end-to-end training/eval skeleton** — simplest possible model first. Get the pipeline working.
3. **Overfit first** — if model can't memorize a single batch, architecture is wrong.
4. **Regularize** — only add dropout, weight decay, augmentation after overfitting confirmed.
5. **Tune** — learning rate is the most important hyperparameter. Use LR finder.
6. **Squeeze** — ensembles, larger models, more data. Diminishing returns here.
## Most Common Neural Net Mistakes
- Not looking at data first.
- Forgetting to set model to eval mode (BatchNorm, Dropout change behavior).
- Forgetting to zero gradients.
- Using softmax with cross-entropy (use logits directly).
- Not normalizing inputs.
- Applying augmentation to validation set.
- Silent shape broadcasting bugs — always assert tensor shapes.
## LLM Insights (Post-GPT Era)
- LLMs are "operating systems" — CPU is the transformer, context window is RAM, training data is disk.
- Tokenization is a key bottleneck — BPE artifacts cause many failure modes.
- Temperature controls creativity vs precision. T=0 for factual, T>0 for creative.
- Chain-of-thought works because it gives the model "working memory" in the output tokens.
- Prompt engineering is programming in natural language. Be explicit, give examples.
## Build Nanograd / Micrograd Philosophy
- Understand backpropagation by implementing it from scratch.
- A neural net is just: forward pass → compute loss → backward pass → update weights.
- Autograd: track operations, build computation graph, reverse-mode differentiation.
- Every complex framework (PyTorch, JAX) is built on these same primitives.
## Practical ML Engineering
- Start simple: logistic regression baseline before deep learning.
- Measure everything: loss curves, gradient norms, weight distributions.
- Reproducibility: fix seeds, log hyperparameters, version datasets.
- Don't trust your code — trust your loss curve. If loss isn't going down, something is wrong.
- Data quality > model complexity. 10x data often beats 10x model size.
## Scaling Laws
- Performance scales predictably with compute, data, and parameters (Chinchilla scaling).
- Compute-optimal training: balance model size and training tokens.
- Emergent abilities appear at scale — capabilities that don't exist in smaller models.
## On AI Engineering
- The best AI engineers understand both ML and systems engineering.
- Inference optimization matters as much as training — quantization, batching, KV-cache.
- Eval is everything. If you can't measure it, you can't improve it.
- Build evaluation suites before building features.
+78
View File
@@ -0,0 +1,78 @@
# AST-Grep (sg) — Structural Code Search & Transform
## Core Concept
- AST-grep searches/transforms code using Abstract Syntax Tree patterns, not regex.
- Pattern matches structural meaning, ignoring whitespace, comments, formatting.
- Works across: Rust, Go, Python, JS/TS, Java, C, C++, Ruby, Kotlin, Lua, CSS, HTML.
## CLI Usage
- `sg --pattern 'unwrap()' -l rust` — find all `.unwrap()` calls in Rust files.
- `sg --pattern 'println!($$$ARGS)' -l rust` — find all println macros with any args.
- `sg --pattern '$A.unwrap()' --rewrite '$A.expect("TODO")' -l rust` — rewrite unwrap to expect.
- `sg scan` — run lint rules from `sgconfig.yml`.
- `sg test` — test rules against fixtures.
## Pattern Syntax
- `$VAR` matches single AST node (identifier, expression, etc).
- `$$$VARS` matches zero or more nodes (variadic).
- `$$VAR` matches zero or one node (optional).
- Literal code matches itself: `if true { $$$BODY }` matches any `if true` block.
## Meta Variables
- `$A` in pattern captures node, available in `--rewrite` as `$A`.
- Named captures: same name must match same content. `$A == $A` matches `x == x` but not `x == y`.
- `$_` is anonymous — matches anything without capturing.
## Rule YAML Format
```yaml
id: no-unwrap
language: rust
rule:
pattern: $A.unwrap()
not:
inside:
kind: test_function
fix: $A.expect("handle error")
message: "Use .expect() instead of .unwrap() in production code"
severity: warning
```
## Composite Rules
- `all: [rule1, rule2]` — both must match.
- `any: [rule1, rule2]` — either matches.
- `not: rule` — negation.
- `matches: rule-id` — reference another rule.
- `inside: { kind: function_item }` — must be inside a function.
- `has: { pattern: $EXPR }` — must contain sub-pattern.
- `follows: { pattern: ... }` — must follow another pattern.
- `precedes: { pattern: ... }` — must precede another pattern.
## Kind Selectors
- `kind: function_item` — match AST node type directly.
- `kind: call_expression` — match function calls.
- Use `sg --debug-query='println!("hello")'` to see AST node kinds.
## Configuration (sgconfig.yml)
```yaml
ruleDirs:
- rules/
testConfigs:
- rules/tests/
```
## Advanced Patterns
- Find unused variables: `let $VAR = $EXPR;` where `$VAR` not referenced later.
- Find API migrations: `old_function($$$ARGS)``new_function($$$ARGS)`.
- Enforce patterns: ensure all error handling uses `?` not `.unwrap()`.
- Security: find `eval($EXPR)`, SQL injection patterns, hardcoded secrets.
## Integration
- CI/CD: `sg scan --json` for machine-readable output.
- Pre-commit hooks: `sg scan --rule rules/` on staged files.
- Editor: VSCode extension, LSP support.
- Programmatic: `@ast-grep/napi` Node.js binding for custom tools.
## vs Regex
- Regex: `unwrap\(\)` matches in comments, strings, docs. AST-grep: only actual code.
- Regex can't match nested structures. AST-grep handles `if { if { unwrap() } }`.
- AST-grep understands scope, types, structure. Regex is text-level.
+38
View File
@@ -0,0 +1,38 @@
# Caveman Communication — Ultra-Compressed Output
## Core Principle
- Cut output tokens 60-70% while keeping 100% technical accuracy.
- Speak like caveman: drop articles, filler, hedging. Keep nouns, verbs, code.
- Every word must carry information. If removing a word doesn't lose meaning, remove it.
## Rules
- No articles (a, an, the) unless ambiguous without them.
- No filler phrases: "I think", "it seems like", "you might want to", "basically".
- No hedging: "perhaps", "maybe", "it's possible that".
- No repetition of what user said. They know what they asked.
- No "Let me" or "I'll" — just do it.
- Code > prose. Show the fix, not a paragraph about the fix.
- Use symbols: → (leads to), ✓ (done/correct), ✗ (wrong), = (equals/means).
## Intensity Levels
- **Lite**: Drop filler, keep sentence structure. "Fix the port conflict by changing 8080 to 8081."
- **Full**: Drop articles, compress sentences. "Fix port conflict — change 8080→8081."
- **Ultra**: Telegraphic. Maximum compression. "port 8080→8081. done."
## Examples
Bad (verbose):
"I think the issue you're experiencing is that the Kubernetes service is trying to bind to port 8080, which is already in use by another process. You might want to try changing the port to 8081 in your deployment manifest."
Good (caveman):
"Port 8080 conflict. Change in deployment.yaml: containerPort: 8081. Restart pod."
## When NOT to Caveman
- User explicitly asks for detailed explanation.
- Teaching a new concept — clarity > brevity.
- Error messages and warnings — be precise.
- Documentation writing — full prose expected.
## Token Savings
- Average English: 1.3 tokens per word. 100 words ≈ 130 tokens.
- Caveman same content: ~35 words ≈ 46 tokens. 65% reduction.
- Over a session: saves thousands of output tokens → more context for actual work.
+85
View File
@@ -0,0 +1,85 @@
# Go (Golang) Skills
## Core Idioms
- Accept interfaces, return structs.
- Errors are values — check them explicitly. `if err != nil { return err }`.
- Don't panic in library code. Reserve panic for truly unrecoverable situations.
- Zero values are useful — `var m map[string]int` is nil but `var s []int` is usable.
## Error Handling
- Wrap errors with context: `fmt.Errorf("failed to open %s: %w", path, err)`.
- Sentinel errors: `var ErrNotFound = errors.New("not found")`. Check with `errors.Is(err, ErrNotFound)`.
- Custom error types: `type ValidationError struct { Field, Message string }`. Check with `errors.As()`.
- Never ignore errors: `_ = doSomething()` is a code smell. At minimum, log it.
## Concurrency
- "Don't communicate by sharing memory; share memory by communicating." — use channels.
- `go func()` launches goroutine. Always ensure goroutines terminate (context, done channel).
- `sync.WaitGroup` to wait for goroutine completion.
- `sync.Mutex` when channels are overkill (protecting a counter, map).
- `context.Context` for cancellation, timeouts, and request-scoped values. Always first parameter.
- `errgroup.Group` for parallel tasks with error propagation.
## Channel Patterns
- `ch := make(chan T)` unbuffered (synchronous). `make(chan T, n)` buffered.
- Fan-out: multiple goroutines read from one channel.
- Fan-in: multiple channels merged into one via select.
- Pipeline: chain of stages connected by channels.
- `select` with `case <-ctx.Done():` for cancellation.
- Close channels from sender side only. Never close from receiver.
## Interfaces
- Interfaces are satisfied implicitly — no `implements` keyword.
- Keep interfaces small: `io.Reader` has one method. `io.ReadWriteCloser` composes three.
- Define interfaces where they're used, not where they're implemented.
- `interface{}` (or `any`) is a code smell — prefer generics or specific interfaces.
- Type assertions: `v, ok := i.(ConcreteType)`. Type switch: `switch v := i.(type) { ... }`.
## Generics (Go 1.18+)
- `func Map[T, U any](s []T, f func(T) U) []U` — generic function.
- Constraints: `comparable`, `~int | ~float64`, custom interface constraints.
- Use generics for data structures and utility functions, not business logic.
## Project Structure
```
cmd/
myapp/main.go # entrypoint
internal/ # private packages
domain/ # business logic, no external deps
repository/ # data access
handler/ # HTTP handlers
pkg/ # public library code
```
- `internal/` enforced by Go compiler — cannot be imported outside module.
- One package per directory. Package name = directory name.
## Testing
- `func TestFoo(t *testing.T)` — test functions.
- Table-driven tests: `tests := []struct{ name string; input int; want int }{ ... }`.
- `t.Run(name, func(t *testing.T) { ... })` for subtests.
- `t.Parallel()` for concurrent test execution.
- `testify/assert` for cleaner assertions. `testify/mock` for mocking.
- `httptest.NewServer()` for HTTP integration tests.
- Benchmarks: `func BenchmarkFoo(b *testing.B) { for i := 0; i < b.N; i++ { ... } }`.
## HTTP Server
- `http.HandlerFunc` wraps functions as handlers.
- Middleware pattern: `func Logging(next http.Handler) http.Handler`.
- Use `chi` or `echo` for routing. Stdlib `http.ServeMux` improved in Go 1.22.
- Always set timeouts: `srv := &http.Server{ReadTimeout: 5*time.Second, WriteTimeout: 10*time.Second}`.
- Graceful shutdown: `signal.Notify` + `srv.Shutdown(ctx)`.
## Performance
- `pprof` for CPU/memory profiling: `go tool pprof http://localhost:6060/debug/pprof/profile`.
- `sync.Pool` for reducing GC pressure on frequently allocated objects.
- Pre-allocate slices: `make([]T, 0, expectedLen)`.
- String building: `strings.Builder` not `+` concatenation.
- Avoid interface boxing in hot paths.
## Common Gotchas
- Loop variable capture in goroutines (fixed in Go 1.22, but still common in older code).
- Nil interface vs nil pointer: `var p *MyType = nil; var i MyInterface = p; i != nil` is TRUE.
- Maps are not safe for concurrent access — use `sync.Map` or `sync.RWMutex`.
- Slice append may or may not create a new backing array — never hold stale slice references.
- `defer` evaluates arguments immediately, runs function at return.
- `init()` runs before `main()` — avoid side effects, prefer explicit initialization.
+63
View File
@@ -0,0 +1,63 @@
# Rust Fundamentals
## Ownership & Borrowing
- Every value has exactly one owner. When owner goes out of scope, value is dropped.
- `&T` immutable borrow, `&mut T` mutable borrow. Cannot have `&mut` while `&` exists.
- Move semantics by default for non-Copy types. Clone for explicit deep copy.
## Lifetimes
- `'a` annotations tell compiler how long references live.
- Elision rules: single input lifetime → applied to all outputs. `&self` → output gets `'self` lifetime.
- `'static` means reference lives for entire program. String literals are `&'static str`.
## Error Handling
- `Result<T, E>` for recoverable errors, `panic!` for unrecoverable.
- `?` operator propagates errors. Use `anyhow::Result` for application code, `thiserror` for library errors.
- Never use `.unwrap()` in production — use `.expect("reason")` or proper error handling.
## Traits & Generics
- Traits define shared behavior: `trait Summary { fn summarize(&self) -> String; }`
- Trait bounds: `fn notify(item: &impl Summary)` or `fn notify<T: Summary>(item: &T)`
- `dyn Trait` for trait objects (dynamic dispatch), `impl Trait` for static dispatch.
- Blanket implementations: `impl<T: Display> ToString for T`
## Smart Pointers
- `Box<T>` heap allocation with single ownership.
- `Rc<T>` reference-counted shared ownership (single-threaded).
- `Arc<T>` atomic reference-counted (thread-safe). Use with `Mutex<T>` or `RwLock<T>`.
- `Cow<'a, T>` clone-on-write — borrows when possible, clones when mutation needed.
## Concurrency
- `Send` — type can be transferred across threads. `Sync` — type can be shared between threads.
- `tokio::spawn` for async tasks. `rayon` for data parallelism.
- Channels: `mpsc::channel()` for multi-producer single-consumer. `crossbeam` for advanced patterns.
- `async/await` — futures are lazy, must be `.await`ed or spawned.
## Pattern Matching
- `match` is exhaustive — must cover all variants.
- `if let Some(x) = option` for single-pattern matching.
- Destructuring: `let (a, b) = tuple;` and `let Point { x, y } = point;`
- Guards: `match x { n if n > 0 => ..., _ => ... }`
## Module System
- `mod foo;` loads from `foo.rs` or `foo/mod.rs`.
- `pub(crate)` visible within crate only. `pub(super)` visible to parent module.
- `use crate::module::Type` absolute path. `use super::Type` relative path.
- Re-exports: `pub use inner::Type;` to flatten module hierarchy.
## Iterators
- `.iter()` borrows, `.into_iter()` consumes, `.iter_mut()` mutable borrow.
- Lazy — nothing happens until consumed (`.collect()`, `.for_each()`, `.count()`).
- Chaining: `.filter().map().flat_map().take().collect::<Vec<_>>()`
- `impl Iterator for MyType { type Item = T; fn next(&mut self) -> Option<Self::Item> }`
## Macros
- `macro_rules!` for declarative macros. `#[derive(...)]` for derive macros.
- `proc_macro` for procedural macros (attribute, derive, function-like).
- `vec![1, 2, 3]` expands to `{ let mut v = Vec::new(); v.push(1); ... v }`
## Common Patterns
- Builder pattern: `MyStruct::new().with_field(val).build()`
- Newtype pattern: `struct UserId(u64);` for type safety without runtime cost.
- Type state pattern: use generics to encode state in the type system.
- Interior mutability: `Cell<T>`, `RefCell<T>` for single-threaded, `Mutex<T>` for multi-threaded.
+69
View File
@@ -0,0 +1,69 @@
# SOLID & DRY Design Principles
## Single Responsibility Principle (SRP)
- A class/module should have one and only one reason to change.
- Each module owns exactly one actor's requirements.
- Bad: `UserService` that handles auth, email, and database. Good: separate `AuthService`, `EmailService`, `UserRepository`.
- In Rust: one struct per concern. `ChunkProcessor` doesn't also handle HTTP routing.
## Open/Closed Principle (OCP)
- Software entities should be open for extension, closed for modification.
- Use traits/interfaces to allow new behavior without changing existing code.
- Strategy pattern: `trait Scorer { fn score(&self, doc: &Doc) -> f64; }` — add new scorers without modifying search.
- In Rust: trait objects or generics. `fn process<S: Strategy>(s: &S)` — new strategies don't touch `process`.
## Liskov Substitution Principle (LSP)
- Subtypes must be substitutable for their base types without breaking correctness.
- If `fn accept(animal: &dyn Animal)` works with `Dog`, it must work with `Cat` too.
- Violated when: subtype throws unexpected errors, ignores base contract, strengthens preconditions.
- In Rust: trait implementations must honor the trait's documented contract.
## Interface Segregation Principle (ISP)
- Clients should not be forced to depend on interfaces they don't use.
- Many small traits > one fat trait.
- Bad: `trait Repository { fn read(); fn write(); fn delete(); fn audit(); }` — read-only clients forced to see write methods.
- Good: `trait Readable`, `trait Writable`, `trait Auditable` — compose as needed.
- In Rust: supertraits for composition: `trait FullRepo: Readable + Writable + Auditable {}`
## Dependency Inversion Principle (DIP)
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- In Rust: accept `impl Trait` or `&dyn Trait`, not concrete types.
- `fn search(store: &dyn VectorStore)` — works with Postgres, OpenSearch, or in-memory mock.
- Constructor injection: `struct SearchEngine { store: Box<dyn VectorStore> }`
## DRY (Don't Repeat Yourself)
- Every piece of knowledge should have a single, unambiguous, authoritative representation.
- DRY is about knowledge, not code. Two functions with same code but different reasons to change are NOT duplication.
- Extract when: same logic appears 3+ times AND changes for the same reason.
- Wrong DRY: coupling unrelated code just because it looks similar. Right DRY: shared business rules in one place.
## WET (Write Everything Twice) — When DRY Goes Wrong
- Premature DRY creates coupling worse than duplication.
- Rule of three: duplicate is fine, triplicate means extract.
- Tests should be WET — readability > DRYness in test code.
- Configuration can be WET — explicit is better than magic shared config.
## KISS (Keep It Simple, Stupid)
- Simplest solution that works is usually the best.
- Avoid: premature abstraction, speculative generality, framework-itis.
- Measure complexity: if a new team member can't understand it in 15 minutes, simplify.
## YAGNI (You Aren't Gonna Need It)
- Don't build features until you actually need them.
- Speculative code rots — it's untested, unmaintained, and misleading.
- Exception: known architectural boundaries (API versioning, database migrations).
## Composition Over Inheritance
- Prefer composing objects over class hierarchies.
- In Rust: no inheritance. Composition is the default via struct fields + trait delegation.
- `struct HttpServer { router: Router, auth: AuthMiddleware, rate_limiter: RateLimiter }`
## Law of Demeter
- Only talk to your immediate friends. Don't chain: `a.b().c().d()`.
- Tell, don't ask: `order.ship()` not `order.get_warehouse().get_shipping().create_label()`.
- In Rust: expose methods that encapsulate internal structure.
## Practical Application
- Start concrete, extract abstractions when patterns emerge.
- Refactor in small steps with tests as safety net.
- Code review checklist: SRP violated? Unnecessary coupling? Duplicated knowledge? Over-engineered?
+65
View File
@@ -0,0 +1,65 @@
{"project":"knowledge","query":"andrej-karpathy:0","run":"latest","turn":0,"event_type":"learn","data":{"chunk_index":0,"level":"L1","sha256":"96fc747c0bcda29f58e27bd541fc24402bca94fcf59038cd9822e66b2e0ac3ce","source":"knowledge/andrej-karpathy.md","text":"# Andrej Karpathy — Key Insights & Practices","total_chunks":9}}
{"project":"knowledge","query":"andrej-karpathy:1","run":"latest","turn":1,"event_type":"learn","data":{"chunk_index":1,"level":"L1","sha256":"bc2e7975fd968bb3323a4109d0236bf8c41e742abaf3bfebbb96cc325c77ec19","source":"knowledge/andrej-karpathy.md","text":"## Software 2.0\n- Traditional software (1.0): explicit rules written by programmers.\n- Software 2.0: behavior learned from data via neural networks. Code = weights.\n- Implication: datasets are the new source code. Data curation > clever algorithms.\n- Debug by inspecting data, not stepping through logic.","total_chunks":9}}
{"project":"knowledge","query":"andrej-karpathy:2","run":"latest","turn":2,"event_type":"learn","data":{"chunk_index":2,"level":"L1","sha256":"b5acf1cd6a76fbeaf16d760d18e2b57113a037a94f6ef2a53d029b4d06699d3b","source":"knowledge/andrej-karpathy.md","text":"## Training Neural Networks — A Recipe\n1. **Become one with the data** — visualize, understand distributions, find patterns and anomalies before writing any model code.\n2. **Set up end-to-end training/eval skeleton** — simplest possible model first. Get the pipeline working.\n3. **Overfit first** — if model can't memorize a single batch, architecture is wrong.\n4. **Regularize** — only add dropout, weight decay, augmentation after overfitting confirmed.\n5. **Tune** — learning rate is the most important hyperparameter. Use LR finder.\n6. **Squeeze** — ensembles, larger models, more data. Diminishing returns here.","total_chunks":9}}
{"project":"knowledge","query":"andrej-karpathy:3","run":"latest","turn":3,"event_type":"learn","data":{"chunk_index":3,"level":"L1","sha256":"8768a071d887b0c38a0a822edf92be2604e029a7ed97634390ce288597a669ee","source":"knowledge/andrej-karpathy.md","text":"## Most Common Neural Net Mistakes\n- Not looking at data first.\n- Forgetting to set model to eval mode (BatchNorm, Dropout change behavior).\n- Forgetting to zero gradients.\n- Using softmax with cross-entropy (use logits directly).\n- Not normalizing inputs.\n- Applying augmentation to validation set.\n- Silent shape broadcasting bugs — always assert tensor shapes.","total_chunks":9}}
{"project":"knowledge","query":"andrej-karpathy:4","run":"latest","turn":4,"event_type":"learn","data":{"chunk_index":4,"level":"L1","sha256":"f8b49eeeb82c80afd8b3e24904abe4a1505fe4af4a3708f5795c307f3aba2396","source":"knowledge/andrej-karpathy.md","text":"## LLM Insights (Post-GPT Era)\n- LLMs are \"operating systems\" — CPU is the transformer, context window is RAM, training data is disk.\n- Tokenization is a key bottleneck — BPE artifacts cause many failure modes.\n- Temperature controls creativity vs precision. T=0 for factual, T>0 for creative.\n- Chain-of-thought works because it gives the model \"working memory\" in the output tokens.\n- Prompt engineering is programming in natural language. Be explicit, give examples.","total_chunks":9}}
{"project":"knowledge","query":"andrej-karpathy:5","run":"latest","turn":5,"event_type":"learn","data":{"chunk_index":5,"level":"L1","sha256":"5bdeb96ce1d96a7a340e955e756044e43a6f65f706dfb27549d5305b7a0edbaa","source":"knowledge/andrej-karpathy.md","text":"## Build Nanograd / Micrograd Philosophy\n- Understand backpropagation by implementing it from scratch.\n- A neural net is just: forward pass → compute loss → backward pass → update weights.\n- Autograd: track operations, build computation graph, reverse-mode differentiation.\n- Every complex framework (PyTorch, JAX) is built on these same primitives.","total_chunks":9}}
{"project":"knowledge","query":"andrej-karpathy:6","run":"latest","turn":6,"event_type":"learn","data":{"chunk_index":6,"level":"L1","sha256":"965a6782e73ba162337b00c2f37d6eecd7ada8ec43a91c39b24c2369e165304b","source":"knowledge/andrej-karpathy.md","text":"## Practical ML Engineering\n- Start simple: logistic regression baseline before deep learning.\n- Measure everything: loss curves, gradient norms, weight distributions.\n- Reproducibility: fix seeds, log hyperparameters, version datasets.\n- Don't trust your code — trust your loss curve. If loss isn't going down, something is wrong.\n- Data quality > model complexity. 10x data often beats 10x model size.","total_chunks":9}}
{"project":"knowledge","query":"andrej-karpathy:7","run":"latest","turn":7,"event_type":"learn","data":{"chunk_index":7,"level":"L1","sha256":"296e684f1b57af077482c6cf83697f36f01b22cf3d32555bde95a001760c5ee4","source":"knowledge/andrej-karpathy.md","text":"## Scaling Laws\n- Performance scales predictably with compute, data, and parameters (Chinchilla scaling).\n- Compute-optimal training: balance model size and training tokens.\n- Emergent abilities appear at scale — capabilities that don't exist in smaller models.","total_chunks":9}}
{"project":"knowledge","query":"andrej-karpathy:8","run":"latest","turn":8,"event_type":"learn","data":{"chunk_index":8,"level":"L1","sha256":"aa6a971d54fafc4ba53aaaf1ba36afe8caf8454ab39698bdd9a20136111335a4","source":"knowledge/andrej-karpathy.md","text":"## On AI Engineering\n- The best AI engineers understand both ML and systems engineering.\n- Inference optimization matters as much as training — quantization, batching, KV-cache.\n- Eval is everything. If you can't measure it, you can't improve it.\n- Build evaluation suites before building features.","total_chunks":9}}
{"project":"knowledge","query":"ast-grep:0","run":"latest","turn":0,"event_type":"learn","data":{"chunk_index":0,"level":"L1","sha256":"938aaf1d005021f300ecda8246052070b35257dc205e1def9e18dd3917c92206","source":"knowledge/ast-grep.md","text":"# AST-Grep (sg) — Structural Code Search & Transform","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:1","run":"latest","turn":1,"event_type":"learn","data":{"chunk_index":1,"level":"L1","sha256":"926ae186e84b30d159dfc3104253b9e204acaf17740833b3a918982931c3ca16","source":"knowledge/ast-grep.md","text":"## Core Concept\n- AST-grep searches/transforms code using Abstract Syntax Tree patterns, not regex.\n- Pattern matches structural meaning, ignoring whitespace, comments, formatting.\n- Works across: Rust, Go, Python, JS/TS, Java, C, C++, Ruby, Kotlin, Lua, CSS, HTML.","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:2","run":"latest","turn":2,"event_type":"learn","data":{"chunk_index":2,"level":"L1","sha256":"3932d5e5acd8bfaf85b0e92fa587b1231f1e9a28b3a58027d7f170daae97bfc9","source":"knowledge/ast-grep.md","text":"## CLI Usage\n- `sg --pattern 'unwrap()' -l rust` — find all `.unwrap()` calls in Rust files.\n- `sg --pattern 'println!($$$ARGS)' -l rust` — find all println macros with any args.\n- `sg --pattern '$A.unwrap()' --rewrite '$A.expect(\"TODO\")' -l rust` — rewrite unwrap to expect.\n- `sg scan` — run lint rules from `sgconfig.yml`.\n- `sg test` — test rules against fixtures.","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:3","run":"latest","turn":3,"event_type":"learn","data":{"chunk_index":3,"level":"L1","sha256":"e3524a773966ec62343402bd8aa0349610889f725fd193e84e9cb9cd90a796a7","source":"knowledge/ast-grep.md","text":"## Pattern Syntax\n- `$VAR` matches single AST node (identifier, expression, etc).\n- `$$$VARS` matches zero or more nodes (variadic).\n- `$$VAR` matches zero or one node (optional).\n- Literal code matches itself: `if true { $$$BODY }` matches any `if true` block.","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:4","run":"latest","turn":4,"event_type":"learn","data":{"chunk_index":4,"level":"L1","sha256":"405b19c2dcb3b59a88faeef7d8ab1eb47d6bf5f4e7c090de9b496b24ee9bb93b","source":"knowledge/ast-grep.md","text":"## Meta Variables\n- `$A` in pattern captures node, available in `--rewrite` as `$A`.\n- Named captures: same name must match same content. `$A == $A` matches `x == x` but not `x == y`.\n- `$_` is anonymous — matches anything without capturing.","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:5","run":"latest","turn":5,"event_type":"learn","data":{"chunk_index":5,"level":"L1","sha256":"2c7d1bb19a23f90fbdb48206839d9c4c13dfe742df28ed4de6cfcaf65cd6414b","source":"knowledge/ast-grep.md","text":"## Rule YAML Format\n```yaml\nid: no-unwrap\nlanguage: rust\nrule:\n pattern: $A.unwrap()\n not:\n inside:\n kind: test_function\nfix: $A.expect(\"handle error\")\nmessage: \"Use .expect() instead of .unwrap() in production code\"\nseverity: warning\n```","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:6","run":"latest","turn":6,"event_type":"learn","data":{"chunk_index":6,"level":"L1","sha256":"7d9376b357ff5d81343cbef5adbd6c3946bf381c673c8c052308c0b1a0d52790","source":"knowledge/ast-grep.md","text":"## Composite Rules\n- `all: [rule1, rule2]` — both must match.\n- `any: [rule1, rule2]` — either matches.\n- `not: rule` — negation.\n- `matches: rule-id` — reference another rule.\n- `inside: { kind: function_item }` — must be inside a function.\n- `has: { pattern: $EXPR }` — must contain sub-pattern.\n- `follows: { pattern: ... }` — must follow another pattern.\n- `precedes: { pattern: ... }` — must precede another pattern.","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:7","run":"latest","turn":7,"event_type":"learn","data":{"chunk_index":7,"level":"L1","sha256":"149ef392299445e1d63e719c0650746b6ea6cfd4f4267414ccf7ca01da2bdf9c","source":"knowledge/ast-grep.md","text":"## Kind Selectors\n- `kind: function_item` — match AST node type directly.\n- `kind: call_expression` — match function calls.\n- Use `sg --debug-query='println!(\"hello\")'` to see AST node kinds.","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:8","run":"latest","turn":8,"event_type":"learn","data":{"chunk_index":8,"level":"L1","sha256":"949924afcbaa21f05d1de58c291c6c05335b647b6ac58a2ae46ba1595400968c","source":"knowledge/ast-grep.md","text":"## Configuration (sgconfig.yml)\n```yaml\nruleDirs:\n - rules/\ntestConfigs:\n - rules/tests/\n```","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:9","run":"latest","turn":9,"event_type":"learn","data":{"chunk_index":9,"level":"L1","sha256":"9931dea657038e2bcf246db03cec83142d0c86acc2a4c1eaf7e0f19c87e7bdf8","source":"knowledge/ast-grep.md","text":"## Advanced Patterns\n- Find unused variables: `let $VAR = $EXPR;` where `$VAR` not referenced later.\n- Find API migrations: `old_function($$$ARGS)` → `new_function($$$ARGS)`.\n- Enforce patterns: ensure all error handling uses `?` not `.unwrap()`.\n- Security: find `eval($EXPR)`, SQL injection patterns, hardcoded secrets.","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:10","run":"latest","turn":10,"event_type":"learn","data":{"chunk_index":10,"level":"L1","sha256":"8fa60c107e2ae5f2a943e2b9106e185cd9641b6ad783fbcfe21a874bc5eb4bd4","source":"knowledge/ast-grep.md","text":"## Integration\n- CI/CD: `sg scan --json` for machine-readable output.\n- Pre-commit hooks: `sg scan --rule rules/` on staged files.\n- Editor: VSCode extension, LSP support.\n- Programmatic: `@ast-grep/napi` Node.js binding for custom tools.","total_chunks":12}}
{"project":"knowledge","query":"ast-grep:11","run":"latest","turn":11,"event_type":"learn","data":{"chunk_index":11,"level":"L1","sha256":"736f7a348fc3d929d781b5fbc13b687de0bfe3b506364f033df4637bb2a8bd28","source":"knowledge/ast-grep.md","text":"## vs Regex\n- Regex: `unwrap\\(\\)` matches in comments, strings, docs. AST-grep: only actual code.\n- Regex can't match nested structures. AST-grep handles `if { if { unwrap() } }`.\n- AST-grep understands scope, types, structure. Regex is text-level.","total_chunks":12}}
{"project":"knowledge","query":"caveman-communication:0","run":"latest","turn":0,"event_type":"learn","data":{"chunk_index":0,"level":"L1","sha256":"69035d3903b4172138b5fddfb4cee9270f8bb1fc5019aa8b812dc279b170abe8","source":"knowledge/caveman-communication.md","text":"# Caveman Communication — Ultra-Compressed Output","total_chunks":7}}
{"project":"knowledge","query":"caveman-communication:1","run":"latest","turn":1,"event_type":"learn","data":{"chunk_index":1,"level":"L1","sha256":"a7996bc7fca36cf342cdc29c4c3fb7914e951ea1041f2b94be69ed085d96021a","source":"knowledge/caveman-communication.md","text":"## Core Principle\n- Cut output tokens 60-70% while keeping 100% technical accuracy.\n- Speak like caveman: drop articles, filler, hedging. Keep nouns, verbs, code.\n- Every word must carry information. If removing a word doesn't lose meaning, remove it.","total_chunks":7}}
{"project":"knowledge","query":"caveman-communication:2","run":"latest","turn":2,"event_type":"learn","data":{"chunk_index":2,"level":"L1","sha256":"b41c9d147a56faac608dadd281e3f8f83f98de679991cad1625f66f305d60f70","source":"knowledge/caveman-communication.md","text":"## Rules\n- No articles (a, an, the) unless ambiguous without them.\n- No filler phrases: \"I think\", \"it seems like\", \"you might want to\", \"basically\".\n- No hedging: \"perhaps\", \"maybe\", \"it's possible that\".\n- No repetition of what user said. They know what they asked.\n- No \"Let me\" or \"I'll\" — just do it.\n- Code > prose. Show the fix, not a paragraph about the fix.\n- Use symbols: → (leads to), ✓ (done/correct), ✗ (wrong), = (equals/means).","total_chunks":7}}
{"project":"knowledge","query":"caveman-communication:3","run":"latest","turn":3,"event_type":"learn","data":{"chunk_index":3,"level":"L1","sha256":"28b85d8ab18ba4c526c3f7fdf67b350b772858b9c0b62f454b1d93bb16fc6ce4","source":"knowledge/caveman-communication.md","text":"## Intensity Levels\n- **Lite**: Drop filler, keep sentence structure. \"Fix the port conflict by changing 8080 to 8081.\"\n- **Full**: Drop articles, compress sentences. \"Fix port conflict — change 8080→8081.\"\n- **Ultra**: Telegraphic. Maximum compression. \"port 8080→8081. done.\"","total_chunks":7}}
{"project":"knowledge","query":"caveman-communication:4","run":"latest","turn":4,"event_type":"learn","data":{"chunk_index":4,"level":"L1","sha256":"28444219d8111bbb9fae3391dc30f2f9f96be99c39b92e81e39036f5c238f0e9","source":"knowledge/caveman-communication.md","text":"## Examples\nBad (verbose):\n\"I think the issue you're experiencing is that the Kubernetes service is trying to bind to port 8080, which is already in use by another process. You might want to try changing the port to 8081 in your deployment manifest.\"\n\nGood (caveman):\n\"Port 8080 conflict. Change in deployment.yaml: containerPort: 8081. Restart pod.\"","total_chunks":7}}
{"project":"knowledge","query":"caveman-communication:5","run":"latest","turn":5,"event_type":"learn","data":{"chunk_index":5,"level":"L1","sha256":"b39e55cff4b18a8a1ade0156d2d56c223e44d0e4e0bee64dd39b9b75da25cd78","source":"knowledge/caveman-communication.md","text":"## When NOT to Caveman\n- User explicitly asks for detailed explanation.\n- Teaching a new concept — clarity > brevity.\n- Error messages and warnings — be precise.\n- Documentation writing — full prose expected.","total_chunks":7}}
{"project":"knowledge","query":"caveman-communication:6","run":"latest","turn":6,"event_type":"learn","data":{"chunk_index":6,"level":"L1","sha256":"2642fc49d0e044e16ff37e990a8a1a1b6d9c96cf937cec715278a61dc10d852f","source":"knowledge/caveman-communication.md","text":"## Token Savings\n- Average English: 1.3 tokens per word. 100 words ≈ 130 tokens.\n- Caveman same content: ~35 words ≈ 46 tokens. 65% reduction.\n- Over a session: saves thousands of output tokens → more context for actual work.","total_chunks":7}}
{"project":"knowledge","query":"golang-skills:0","run":"latest","turn":0,"event_type":"learn","data":{"chunk_index":0,"level":"L1","sha256":"307bfa816f5657b69cfcd94a2582713263adc3a5c32532f6d47fd3be3c535e16","source":"knowledge/golang-skills.md","text":"# Go (Golang) Skills","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:1","run":"latest","turn":1,"event_type":"learn","data":{"chunk_index":1,"level":"L1","sha256":"a1fe77aaa004f914a14b51e920ad0eb0992e6ea3b5f1e3b912389f6a6821f3f0","source":"knowledge/golang-skills.md","text":"## Core Idioms\n- Accept interfaces, return structs.\n- Errors are values — check them explicitly. `if err != nil { return err }`.\n- Don't panic in library code. Reserve panic for truly unrecoverable situations.\n- Zero values are useful — `var m map[string]int` is nil but `var s []int` is usable.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:2","run":"latest","turn":2,"event_type":"learn","data":{"chunk_index":2,"level":"L1","sha256":"e5476fdaa6443f6a5d61dcfd780a2468c933ea93240f7413f02ceccac5a38647","source":"knowledge/golang-skills.md","text":"## Error Handling\n- Wrap errors with context: `fmt.Errorf(\"failed to open %s: %w\", path, err)`.\n- Sentinel errors: `var ErrNotFound = errors.New(\"not found\")`. Check with `errors.Is(err, ErrNotFound)`.\n- Custom error types: `type ValidationError struct { Field, Message string }`. Check with `errors.As()`.\n- Never ignore errors: `_ = doSomething()` is a code smell. At minimum, log it.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:3","run":"latest","turn":3,"event_type":"learn","data":{"chunk_index":3,"level":"L1","sha256":"d31c0300bb450c928105c5393a8267f4b5995559dd1355c4c0ec0c88c7e4850c","source":"knowledge/golang-skills.md","text":"## Concurrency\n- \"Don't communicate by sharing memory; share memory by communicating.\" — use channels.\n- `go func()` launches goroutine. Always ensure goroutines terminate (context, done channel).\n- `sync.WaitGroup` to wait for goroutine completion.\n- `sync.Mutex` when channels are overkill (protecting a counter, map).\n- `context.Context` for cancellation, timeouts, and request-scoped values. Always first parameter.\n- `errgroup.Group` for parallel tasks with error propagation.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:4","run":"latest","turn":4,"event_type":"learn","data":{"chunk_index":4,"level":"L1","sha256":"4b9d554419821786d90683057cc49429c9dbb4e4bda9e2637caa9829bf32710d","source":"knowledge/golang-skills.md","text":"## Channel Patterns\n- `ch := make(chan T)` unbuffered (synchronous). `make(chan T, n)` buffered.\n- Fan-out: multiple goroutines read from one channel.\n- Fan-in: multiple channels merged into one via select.\n- Pipeline: chain of stages connected by channels.\n- `select` with `case <-ctx.Done():` for cancellation.\n- Close channels from sender side only. Never close from receiver.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:5","run":"latest","turn":5,"event_type":"learn","data":{"chunk_index":5,"level":"L1","sha256":"5bc4131050a7e4a04dfcb611651d0549d7fd0b6897c732434fc4fb52992b5ba1","source":"knowledge/golang-skills.md","text":"## Interfaces\n- Interfaces are satisfied implicitly — no `implements` keyword.\n- Keep interfaces small: `io.Reader` has one method. `io.ReadWriteCloser` composes three.\n- Define interfaces where they're used, not where they're implemented.\n- `interface{}` (or `any`) is a code smell — prefer generics or specific interfaces.\n- Type assertions: `v, ok := i.(ConcreteType)`. Type switch: `switch v := i.(type) { ... }`.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:6","run":"latest","turn":6,"event_type":"learn","data":{"chunk_index":6,"level":"L1","sha256":"51d99bf523bdf2d615cc9081f81ca5699268b0658ea4c8143406df14c32f1bb6","source":"knowledge/golang-skills.md","text":"## Generics (Go 1.18+)\n- `func Map[T, U any](s []T, f func(T) U) []U` — generic function.\n- Constraints: `comparable`, `~int | ~float64`, custom interface constraints.\n- Use generics for data structures and utility functions, not business logic.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:7","run":"latest","turn":7,"event_type":"learn","data":{"chunk_index":7,"level":"L1","sha256":"21bf4ec3471d9712b9d62cc8cee1fa27261c6ddfa74d65c0e65f58ee400b8c4c","source":"knowledge/golang-skills.md","text":"## Project Structure\n```\ncmd/\n myapp/main.go # entrypoint\ninternal/ # private packages\n domain/ # business logic, no external deps\n repository/ # data access\n handler/ # HTTP handlers\npkg/ # public library code\n```\n- `internal/` enforced by Go compiler — cannot be imported outside module.\n- One package per directory. Package name = directory name.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:8","run":"latest","turn":8,"event_type":"learn","data":{"chunk_index":8,"level":"L1","sha256":"c1210d8d99a94ce28e581ff93beedbcf1fd6a236b3a314bc73b0e9784bbd05ef","source":"knowledge/golang-skills.md","text":"## Testing\n- `func TestFoo(t *testing.T)` — test functions.\n- Table-driven tests: `tests := []struct{ name string; input int; want int }{ ... }`.\n- `t.Run(name, func(t *testing.T) { ... })` for subtests.\n- `t.Parallel()` for concurrent test execution.\n- `testify/assert` for cleaner assertions. `testify/mock` for mocking.\n- `httptest.NewServer()` for HTTP integration tests.\n- Benchmarks: `func BenchmarkFoo(b *testing.B) { for i := 0; i < b.N; i++ { ... } }`.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:9","run":"latest","turn":9,"event_type":"learn","data":{"chunk_index":9,"level":"L1","sha256":"925cdfafae3fcfa87c5a792565582a8f6170e6cdd3a35f3b5861f4c8a09895b9","source":"knowledge/golang-skills.md","text":"## HTTP Server\n- `http.HandlerFunc` wraps functions as handlers.\n- Middleware pattern: `func Logging(next http.Handler) http.Handler`.\n- Use `chi` or `echo` for routing. Stdlib `http.ServeMux` improved in Go 1.22.\n- Always set timeouts: `srv := &http.Server{ReadTimeout: 5*time.Second, WriteTimeout: 10*time.Second}`.\n- Graceful shutdown: `signal.Notify` + `srv.Shutdown(ctx)`.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:10","run":"latest","turn":10,"event_type":"learn","data":{"chunk_index":10,"level":"L1","sha256":"19d6e7a82d2c7bb00f492fcb68f51f961467ec78227ba42a9ee0ec4844d7cb2d","source":"knowledge/golang-skills.md","text":"## Performance\n- `pprof` for CPU/memory profiling: `go tool pprof http://localhost:6060/debug/pprof/profile`.\n- `sync.Pool` for reducing GC pressure on frequently allocated objects.\n- Pre-allocate slices: `make([]T, 0, expectedLen)`.\n- String building: `strings.Builder` not `+` concatenation.\n- Avoid interface boxing in hot paths.","total_chunks":12}}
{"project":"knowledge","query":"golang-skills:11","run":"latest","turn":11,"event_type":"learn","data":{"chunk_index":11,"level":"L1","sha256":"5a872b66f1a89f540f08ece84d9c040d68e3236ffd71cb981cc5d371b991d20f","source":"knowledge/golang-skills.md","text":"## Common Gotchas\n- Loop variable capture in goroutines (fixed in Go 1.22, but still common in older code).\n- Nil interface vs nil pointer: `var p *MyType = nil; var i MyInterface = p; i != nil` is TRUE.\n- Maps are not safe for concurrent access — use `sync.Map` or `sync.RWMutex`.\n- Slice append may or may not create a new backing array — never hold stale slice references.\n- `defer` evaluates arguments immediately, runs function at return.\n- `init()` runs before `main()` — avoid side effects, prefer explicit initialization.","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:0","run":"latest","turn":0,"event_type":"learn","data":{"chunk_index":0,"level":"L1","sha256":"938a5b95800adb2f3bddc13bc3b793170e678c308e4d4661dfc994fb38692659","source":"knowledge/rust-fundamentals.md","text":"# Rust Fundamentals","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:1","run":"latest","turn":1,"event_type":"learn","data":{"chunk_index":1,"level":"L1","sha256":"40f33225751c58fd80b9960c6daf90cf2bfb005f03f2db4b1761ec739a7e44cb","source":"knowledge/rust-fundamentals.md","text":"## Ownership & Borrowing\n- Every value has exactly one owner. When owner goes out of scope, value is dropped.\n- `&T` immutable borrow, `&mut T` mutable borrow. Cannot have `&mut` while `&` exists.\n- Move semantics by default for non-Copy types. Clone for explicit deep copy.","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:2","run":"latest","turn":2,"event_type":"learn","data":{"chunk_index":2,"level":"L1","sha256":"4c3838041a71cf0d3b9a3203eb1733c698bbc87d6dd201c159344f56a231b07c","source":"knowledge/rust-fundamentals.md","text":"## Lifetimes\n- `'a` annotations tell compiler how long references live.\n- Elision rules: single input lifetime → applied to all outputs. `&self` → output gets `'self` lifetime.\n- `'static` means reference lives for entire program. String literals are `&'static str`.","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:3","run":"latest","turn":3,"event_type":"learn","data":{"chunk_index":3,"level":"L1","sha256":"6f51e7f86ccef640864780050e660757cc868d20faad5642fa4f1e6e52fcbd54","source":"knowledge/rust-fundamentals.md","text":"## Error Handling\n- `Result<T, E>` for recoverable errors, `panic!` for unrecoverable.\n- `?` operator propagates errors. Use `anyhow::Result` for application code, `thiserror` for library errors.\n- Never use `.unwrap()` in production — use `.expect(\"reason\")` or proper error handling.","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:4","run":"latest","turn":4,"event_type":"learn","data":{"chunk_index":4,"level":"L1","sha256":"7f2ecd5e8344f9aacc2310acd018f2367bd8b3b5b165484e43e08088eb621a81","source":"knowledge/rust-fundamentals.md","text":"## Traits & Generics\n- Traits define shared behavior: `trait Summary { fn summarize(&self) -> String; }`\n- Trait bounds: `fn notify(item: &impl Summary)` or `fn notify<T: Summary>(item: &T)`\n- `dyn Trait` for trait objects (dynamic dispatch), `impl Trait` for static dispatch.\n- Blanket implementations: `impl<T: Display> ToString for T`","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:5","run":"latest","turn":5,"event_type":"learn","data":{"chunk_index":5,"level":"L1","sha256":"e64dd65ddf651cb176b7507bfd92d97ecc4263e02574741ef62e813cfff3551d","source":"knowledge/rust-fundamentals.md","text":"## Smart Pointers\n- `Box<T>` heap allocation with single ownership.\n- `Rc<T>` reference-counted shared ownership (single-threaded).\n- `Arc<T>` atomic reference-counted (thread-safe). Use with `Mutex<T>` or `RwLock<T>`.\n- `Cow<'a, T>` clone-on-write — borrows when possible, clones when mutation needed.","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:6","run":"latest","turn":6,"event_type":"learn","data":{"chunk_index":6,"level":"L1","sha256":"3f69f64923035ec5cd075ec2e15b3ed2f035949ad052285da103ef6a90d180a0","source":"knowledge/rust-fundamentals.md","text":"## Concurrency\n- `Send` — type can be transferred across threads. `Sync` — type can be shared between threads.\n- `tokio::spawn` for async tasks. `rayon` for data parallelism.\n- Channels: `mpsc::channel()` for multi-producer single-consumer. `crossbeam` for advanced patterns.\n- `async/await` — futures are lazy, must be `.await`ed or spawned.","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:7","run":"latest","turn":7,"event_type":"learn","data":{"chunk_index":7,"level":"L1","sha256":"b8f8fc26834fe910d6434a529cddd11339ade3dc2ae32dd378c2875b7d72e149","source":"knowledge/rust-fundamentals.md","text":"## Pattern Matching\n- `match` is exhaustive — must cover all variants.\n- `if let Some(x) = option` for single-pattern matching.\n- Destructuring: `let (a, b) = tuple;` and `let Point { x, y } = point;`\n- Guards: `match x { n if n > 0 => ..., _ => ... }`","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:8","run":"latest","turn":8,"event_type":"learn","data":{"chunk_index":8,"level":"L1","sha256":"bccdf62a0b7c9be157961e5c36f2d962fc53ec24009e0686ecae0691aa933f3c","source":"knowledge/rust-fundamentals.md","text":"## Module System\n- `mod foo;` loads from `foo.rs` or `foo/mod.rs`.\n- `pub(crate)` visible within crate only. `pub(super)` visible to parent module.\n- `use crate::module::Type` absolute path. `use super::Type` relative path.\n- Re-exports: `pub use inner::Type;` to flatten module hierarchy.","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:9","run":"latest","turn":9,"event_type":"learn","data":{"chunk_index":9,"level":"L1","sha256":"746c2db8686ce1f93e7ccd39e7617ee9db7708f0cf2b8dcf5f93cd61a1d2fc87","source":"knowledge/rust-fundamentals.md","text":"## Iterators\n- `.iter()` borrows, `.into_iter()` consumes, `.iter_mut()` mutable borrow.\n- Lazy — nothing happens until consumed (`.collect()`, `.for_each()`, `.count()`).\n- Chaining: `.filter().map().flat_map().take().collect::<Vec<_>>()`\n- `impl Iterator for MyType { type Item = T; fn next(&mut self) -> Option<Self::Item> }`","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:10","run":"latest","turn":10,"event_type":"learn","data":{"chunk_index":10,"level":"L1","sha256":"4981e3e218a0c6f17546dc9b7385351115066ae01cde02588feb82a567085495","source":"knowledge/rust-fundamentals.md","text":"## Macros\n- `macro_rules!` for declarative macros. `#[derive(...)]` for derive macros.\n- `proc_macro` for procedural macros (attribute, derive, function-like).\n- `vec![1, 2, 3]` expands to `{ let mut v = Vec::new(); v.push(1); ... v }`","total_chunks":12}}
{"project":"knowledge","query":"rust-fundamentals:11","run":"latest","turn":11,"event_type":"learn","data":{"chunk_index":11,"level":"L1","sha256":"4c137d96c638eaa8922a353b4ff70e20c4edcad6a3995b5524bdd04ec6439586","source":"knowledge/rust-fundamentals.md","text":"## Common Patterns\n- Builder pattern: `MyStruct::new().with_field(val).build()`\n- Newtype pattern: `struct UserId(u64);` for type safety without runtime cost.\n- Type state pattern: use generics to encode state in the type system.\n- Interior mutability: `Cell<T>`, `RefCell<T>` for single-threaded, `Mutex<T>` for multi-threaded.","total_chunks":12}}
{"project":"knowledge","query":"solid-dry-principles:0","run":"latest","turn":0,"event_type":"learn","data":{"chunk_index":0,"level":"L1","sha256":"7721d79c72c3b3c2dfa2b0acf902bfe1a2da7d622f9472c15a3e08fc51c76cb3","source":"knowledge/solid-dry-principles.md","text":"# SOLID & DRY Design Principles","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:1","run":"latest","turn":1,"event_type":"learn","data":{"chunk_index":1,"level":"L1","sha256":"3fd2840a348033491348006884d34089184f072f6b71a43afc0331ba84184d77","source":"knowledge/solid-dry-principles.md","text":"## Single Responsibility Principle (SRP)\n- A class/module should have one and only one reason to change.\n- Each module owns exactly one actor's requirements.\n- Bad: `UserService` that handles auth, email, and database. Good: separate `AuthService`, `EmailService`, `UserRepository`.\n- In Rust: one struct per concern. `ChunkProcessor` doesn't also handle HTTP routing.","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:2","run":"latest","turn":2,"event_type":"learn","data":{"chunk_index":2,"level":"L1","sha256":"927592c6c68dbd42ab38b31d39c7b81f4160a180c24b8d71b2d1e6197168c1eb","source":"knowledge/solid-dry-principles.md","text":"## Open/Closed Principle (OCP)\n- Software entities should be open for extension, closed for modification.\n- Use traits/interfaces to allow new behavior without changing existing code.\n- Strategy pattern: `trait Scorer { fn score(&self, doc: &Doc) -> f64; }` — add new scorers without modifying search.\n- In Rust: trait objects or generics. `fn process<S: Strategy>(s: &S)` — new strategies don't touch `process`.","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:3","run":"latest","turn":3,"event_type":"learn","data":{"chunk_index":3,"level":"L1","sha256":"1c6d960c61ff7a8b5b6dd7b26c70ac88884da0bcc3cc568fb05b2c74687cec0e","source":"knowledge/solid-dry-principles.md","text":"## Liskov Substitution Principle (LSP)\n- Subtypes must be substitutable for their base types without breaking correctness.\n- If `fn accept(animal: &dyn Animal)` works with `Dog`, it must work with `Cat` too.\n- Violated when: subtype throws unexpected errors, ignores base contract, strengthens preconditions.\n- In Rust: trait implementations must honor the trait's documented contract.","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:4","run":"latest","turn":4,"event_type":"learn","data":{"chunk_index":4,"level":"L1","sha256":"972c4a715547bc6028099526d21dd2c30c2942c8ccc1910a0dfd58af0c40125e","source":"knowledge/solid-dry-principles.md","text":"## Interface Segregation Principle (ISP)\n- Clients should not be forced to depend on interfaces they don't use.\n- Many small traits > one fat trait.\n- Bad: `trait Repository { fn read(); fn write(); fn delete(); fn audit(); }` — read-only clients forced to see write methods.\n- Good: `trait Readable`, `trait Writable`, `trait Auditable` — compose as needed.\n- In Rust: supertraits for composition: `trait FullRepo: Readable + Writable + Auditable {}`","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:5","run":"latest","turn":5,"event_type":"learn","data":{"chunk_index":5,"level":"L1","sha256":"e52391adbdeceb264716cda68857f5bee8563183cc9692681d215305e6454ea5","source":"knowledge/solid-dry-principles.md","text":"## Dependency Inversion Principle (DIP)\n- High-level modules should not depend on low-level modules. Both should depend on abstractions.\n- In Rust: accept `impl Trait` or `&dyn Trait`, not concrete types.\n- `fn search(store: &dyn VectorStore)` — works with Postgres, OpenSearch, or in-memory mock.\n- Constructor injection: `struct SearchEngine { store: Box<dyn VectorStore> }`","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:6","run":"latest","turn":6,"event_type":"learn","data":{"chunk_index":6,"level":"L1","sha256":"edcdeee3a6c405e2adad092d78b8f5f6f7beed778649c36780bc677418a21e7c","source":"knowledge/solid-dry-principles.md","text":"## DRY (Don't Repeat Yourself)\n- Every piece of knowledge should have a single, unambiguous, authoritative representation.\n- DRY is about knowledge, not code. Two functions with same code but different reasons to change are NOT duplication.\n- Extract when: same logic appears 3+ times AND changes for the same reason.\n- Wrong DRY: coupling unrelated code just because it looks similar. Right DRY: shared business rules in one place.","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:7","run":"latest","turn":7,"event_type":"learn","data":{"chunk_index":7,"level":"L1","sha256":"774b41e79a231bcd65412b85d255252736f202e3c85c35167ceac005499e74d0","source":"knowledge/solid-dry-principles.md","text":"## WET (Write Everything Twice) — When DRY Goes Wrong\n- Premature DRY creates coupling worse than duplication.\n- Rule of three: duplicate is fine, triplicate means extract.\n- Tests should be WET — readability > DRYness in test code.\n- Configuration can be WET — explicit is better than magic shared config.","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:8","run":"latest","turn":8,"event_type":"learn","data":{"chunk_index":8,"level":"L1","sha256":"dc611d933234e9bf4cd2f7f1b077237564c21305ecaa4b9bf1e772b8830e1936","source":"knowledge/solid-dry-principles.md","text":"## KISS (Keep It Simple, Stupid)\n- Simplest solution that works is usually the best.\n- Avoid: premature abstraction, speculative generality, framework-itis.\n- Measure complexity: if a new team member can't understand it in 15 minutes, simplify.","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:9","run":"latest","turn":9,"event_type":"learn","data":{"chunk_index":9,"level":"L1","sha256":"1fca71e8e16d245085dbe72d12ad950fa10fc431ae018d0fc196dec11cbfa195","source":"knowledge/solid-dry-principles.md","text":"## YAGNI (You Aren't Gonna Need It)\n- Don't build features until you actually need them.\n- Speculative code rots — it's untested, unmaintained, and misleading.\n- Exception: known architectural boundaries (API versioning, database migrations).","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:10","run":"latest","turn":10,"event_type":"learn","data":{"chunk_index":10,"level":"L1","sha256":"e5fb640cbedc9f409f3fd73978f0578f2af62c89df104ec3054d1f19579179f7","source":"knowledge/solid-dry-principles.md","text":"## Composition Over Inheritance\n- Prefer composing objects over class hierarchies.\n- In Rust: no inheritance. Composition is the default via struct fields + trait delegation.\n- `struct HttpServer { router: Router, auth: AuthMiddleware, rate_limiter: RateLimiter }`","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:11","run":"latest","turn":11,"event_type":"learn","data":{"chunk_index":11,"level":"L1","sha256":"0606d00ead93bf2f15c0e75447791e02ada10a1eef34e8ea5de20f7d705642e8","source":"knowledge/solid-dry-principles.md","text":"## Law of Demeter\n- Only talk to your immediate friends. Don't chain: `a.b().c().d()`.\n- Tell, don't ask: `order.ship()` not `order.get_warehouse().get_shipping().create_label()`.\n- In Rust: expose methods that encapsulate internal structure.","total_chunks":13}}
{"project":"knowledge","query":"solid-dry-principles:12","run":"latest","turn":12,"event_type":"learn","data":{"chunk_index":12,"level":"L1","sha256":"4eaad9bdaf561bc037d4bf306d8838bc7341f117ef3cd28cd9be5571d4262548","source":"knowledge/solid-dry-principles.md","text":"## Practical Application\n- Start concrete, extract abstractions when patterns emerge.\n- Refactor in small steps with tests as safety net.\n- Code review checklist: SRP violated? Unnecessary coupling? Duplicated knowledge? Over-engineered?","total_chunks":13}}