1use super::types::{
7 KnowledgeItem, KnowledgeMatch, KnowledgeQuery, KnowledgeReference, LoadCondition,
8};
9use std::collections::HashMap;
10use std::fs;
11use std::path::{Path, PathBuf};
12use std::sync::RwLock;
13
14#[derive(Debug, thiserror::Error)]
16pub enum KnowledgeError {
17 #[error("Knowledge item not found: {0}")]
18 NotFound(String),
19 #[error("Failed to load knowledge: {0}")]
20 LoadError(String),
21 #[error("Failed to parse knowledge file: {0}")]
22 ParseError(String),
23 #[error("Invalid knowledge id: {0}")]
24 InvalidId(String),
25 #[error("Forbidden operation: {0}")]
26 Forbidden(String),
27 #[error("IO error: {0}")]
28 IoError(#[from] std::io::Error),
29}
30
31const ORIGIN_KEY: &str = "origin";
32const ORIGIN_BUILTIN: &str = "builtin";
33const ORIGIN_USER: &str = "user";
34
35pub struct KnowledgeStore {
37 items: RwLock<HashMap<String, KnowledgeItem>>,
39 base_dir: PathBuf,
41 reference_cache: RwLock<HashMap<String, String>>,
43}
44
45impl KnowledgeStore {
46 pub fn new(base_dir: impl Into<PathBuf>) -> Self {
48 Self {
49 items: RwLock::new(HashMap::new()),
50 base_dir: base_dir.into(),
51 reference_cache: RwLock::new(HashMap::new()),
52 }
53 }
54
55 pub fn with_default_dir() -> Self {
57 let base_dir = dirs::config_dir()
58 .unwrap_or_else(|| PathBuf::from("."))
59 .join("gestura")
60 .join("knowledge");
61 Self::new(base_dir)
62 }
63
64 pub fn base_dir(&self) -> &Path {
66 &self.base_dir
67 }
68
69 pub fn register(&self, item: KnowledgeItem) {
71 let mut items = self.items.write().unwrap();
72 items.insert(item.id.clone(), item);
73 }
74
75 fn validate_id(id: &str) -> Result<(), KnowledgeError> {
76 let trimmed = id.trim();
77 if trimmed.is_empty() {
78 return Err(KnowledgeError::InvalidId("id cannot be empty".to_string()));
79 }
80 if trimmed.contains('/') || trimmed.contains('\\') || trimmed.contains("..") {
81 return Err(KnowledgeError::InvalidId(format!(
82 "id contains illegal path characters: {trimmed}"
83 )));
84 }
85 Ok(())
86 }
87
88 fn item_dir(&self, id: &str) -> PathBuf {
89 self.base_dir.join(id)
90 }
91
92 fn item_json_path(&self, id: &str) -> PathBuf {
93 self.item_dir(id).join("item.json")
94 }
95
96 pub fn load_user_items(&self) -> Result<usize, KnowledgeError> {
101 fs::create_dir_all(&self.base_dir)?;
102
103 let mut loaded = 0usize;
104 let entries = match fs::read_dir(&self.base_dir) {
105 Ok(e) => e,
106 Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(0),
107 Err(e) => return Err(KnowledgeError::IoError(e)),
108 };
109
110 for entry in entries {
111 let entry = match entry {
112 Ok(e) => e,
113 Err(e) => {
114 tracing::warn!(error = %e, "Skipping unreadable knowledge dir entry");
115 continue;
116 }
117 };
118
119 let path = entry.path();
120 if !path.is_dir() {
121 continue;
122 }
123
124 let item_path = path.join("item.json");
125 if !item_path.exists() {
126 continue;
127 }
128
129 let raw = match fs::read_to_string(&item_path) {
130 Ok(s) => s,
131 Err(e) => {
132 tracing::warn!(path = %item_path.display(), error = %e, "Skipping unreadable knowledge item");
133 continue;
134 }
135 };
136
137 let mut item: KnowledgeItem = match serde_json::from_str(&raw) {
138 Ok(v) => v,
139 Err(e) => {
140 tracing::warn!(path = %item_path.display(), error = %e, "Skipping unparseable knowledge item");
141 continue;
142 }
143 };
144
145 if let Err(e) = Self::validate_id(&item.id) {
146 tracing::warn!(path = %item_path.display(), error = %e, "Skipping knowledge item with invalid id");
147 continue;
148 }
149
150 item.metadata
152 .insert(ORIGIN_KEY.to_string(), ORIGIN_USER.to_string());
153
154 if let Some(existing) = self.get(&item.id)
156 && existing
157 .metadata
158 .get(ORIGIN_KEY)
159 .is_some_and(|v| v == ORIGIN_BUILTIN)
160 {
161 tracing::warn!(id = %item.id, "Skipping user item that collides with a builtin id");
162 continue;
163 }
164
165 self.register(item);
166 loaded += 1;
167 }
168
169 Ok(loaded)
170 }
171
172 pub fn upsert_user_item(&self, mut item: KnowledgeItem) -> Result<(), KnowledgeError> {
174 Self::validate_id(&item.id)?;
175
176 if let Some(existing) = self.get(&item.id)
178 && existing
179 .metadata
180 .get(ORIGIN_KEY)
181 .is_some_and(|v| v == ORIGIN_BUILTIN)
182 {
183 return Err(KnowledgeError::Forbidden(format!(
184 "cannot modify builtin knowledge item: {}",
185 item.id
186 )));
187 }
188
189 item.metadata
190 .insert(ORIGIN_KEY.to_string(), ORIGIN_USER.to_string());
191
192 let dir = self.item_dir(&item.id);
193 fs::create_dir_all(&dir)?;
194
195 let path = self.item_json_path(&item.id);
196 let tmp_path = path.with_extension("json.tmp");
197 let raw = serde_json::to_string_pretty(&item)
198 .map_err(|e| KnowledgeError::ParseError(e.to_string()))?;
199
200 fs::write(&tmp_path, raw)?;
201 fs::rename(&tmp_path, &path)?;
202
203 self.register(item);
204 Ok(())
205 }
206
207 pub fn delete_user_item(&self, id: &str) -> Result<(), KnowledgeError> {
209 Self::validate_id(id)?;
210
211 let existing = self
212 .get(id)
213 .ok_or_else(|| KnowledgeError::NotFound(id.to_string()))?;
214 let origin = existing.metadata.get(ORIGIN_KEY).map(|s| s.as_str());
215 if origin == Some(ORIGIN_BUILTIN) {
216 return Err(KnowledgeError::Forbidden(format!(
217 "cannot delete builtin knowledge item: {id}"
218 )));
219 }
220
221 let dir = self.item_dir(id);
222 if dir.exists() {
223 fs::remove_dir_all(&dir)?;
224 }
225
226 {
227 let mut items = self.items.write().unwrap();
228 items.remove(id);
229 }
230 self.clear_cache();
231 Ok(())
232 }
233
234 pub fn register_all(&self, items: impl IntoIterator<Item = KnowledgeItem>) {
236 let mut store = self.items.write().unwrap();
237 for item in items {
238 store.insert(item.id.clone(), item);
239 }
240 }
241
242 pub fn get(&self, id: &str) -> Option<KnowledgeItem> {
244 let items = self.items.read().unwrap();
245 items.get(id).cloned()
246 }
247
248 pub fn list(&self) -> Vec<KnowledgeItem> {
250 let items = self.items.read().unwrap();
251 items.values().cloned().collect()
252 }
253
254 pub fn list_by_category(&self, category: &str) -> Vec<KnowledgeItem> {
256 let items = self.items.read().unwrap();
257 items
258 .values()
259 .filter(|item| item.category == category)
260 .cloned()
261 .collect()
262 }
263
264 pub fn find(&self, query: &KnowledgeQuery) -> Vec<KnowledgeMatch> {
269 let items = self.items.read().unwrap();
270 let mut matches: Vec<KnowledgeMatch> = items
271 .values()
272 .filter(|item| {
273 if let Some(ref cats) = query.categories {
274 cats.contains(&item.category)
275 } else {
276 true
277 }
278 })
279 .filter_map(|item| item.matches(&query.query))
280 .filter(|m| m.score >= query.min_score.unwrap_or(0.1))
281 .collect();
282
283 matches.sort_by(|a, b| {
285 b.score
286 .partial_cmp(&a.score)
287 .unwrap_or(std::cmp::Ordering::Equal)
288 .then_with(|| b.item.priority.cmp(&a.item.priority))
289 });
290
291 if let Some(limit) = query.limit {
292 matches.truncate(limit);
293 }
294
295 matches
296 }
297
298 pub fn load_reference(&self, item_id: &str, ref_id: &str) -> Result<String, KnowledgeError> {
300 let cache_key = format!("{}:{}", item_id, ref_id);
301
302 {
304 let cache = self.reference_cache.read().unwrap();
305 if let Some(content) = cache.get(&cache_key) {
306 return Ok(content.clone());
307 }
308 }
309
310 let items = self.items.read().unwrap();
312 let item = items
313 .get(item_id)
314 .ok_or_else(|| KnowledgeError::NotFound(item_id.to_string()))?;
315
316 let reference = item
317 .references
318 .iter()
319 .find(|r| r.id == ref_id)
320 .ok_or_else(|| KnowledgeError::NotFound(format!("{}:{}", item_id, ref_id)))?;
321
322 let ref_path = self.base_dir.join(&item.id).join(&reference.path);
324 let content = std::fs::read_to_string(&ref_path).map_err(|e| {
325 KnowledgeError::LoadError(format!("Failed to load {}: {}", ref_path.display(), e))
326 })?;
327
328 {
330 let mut cache = self.reference_cache.write().unwrap();
331 cache.insert(cache_key, content.clone());
332 }
333
334 Ok(content)
335 }
336
337 pub fn categories(&self) -> Vec<String> {
339 let items = self.items.read().unwrap();
340 let mut cats: Vec<String> = items.values().map(|i| i.category.clone()).collect();
341 cats.sort();
342 cats.dedup();
343 cats
344 }
345
346 pub fn count(&self) -> usize {
348 self.items.read().unwrap().len()
349 }
350
351 pub fn set_enabled(&self, id: &str, enabled: bool) -> Result<(), KnowledgeError> {
353 let mut items = self.items.write().unwrap();
354 let item = items
355 .get_mut(id)
356 .ok_or_else(|| KnowledgeError::NotFound(id.to_string()))?;
357 item.enabled = enabled;
358 Ok(())
359 }
360
361 pub fn clear_cache(&self) {
363 let mut cache = self.reference_cache.write().unwrap();
364 cache.clear();
365 }
366}
367
368pub fn register_builtin_knowledge(store: &KnowledgeStore) {
370 store.register_all(builtin_knowledge_items());
371}
372
373fn builtin_knowledge_items() -> Vec<KnowledgeItem> {
375 let mut items = vec![
376 KnowledgeItem::new(
378 "rust-expert",
379 "Rust Expert",
380 "Expert Rust programming with Cargo, ownership, async Tokio, Serde, and robust error handling",
381 )
382 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
383 .with_triggers([
384 "rust",
385 "cargo",
386 "cargo fmt",
387 "cargo clippy",
388 "ownership",
389 "borrowing",
390 "lifetime",
391 "serde",
392 "tracing",
393 "thiserror",
394 "anyhow",
395 "async rust",
396 "tokio",
397 ])
398 .with_category("language")
399 .with_content(include_str!("builtin/rust_expert.md"))
400 .with_reference(
401 KnowledgeReference::new("async", "Async Rust", "references/async.md")
402 .with_load_condition(LoadCondition::Keywords(vec![
403 "async".into(),
404 "tokio".into(),
405 "future".into(),
406 ])),
407 )
408 .with_reference(
409 KnowledgeReference::new("error-handling", "Error Handling", "references/errors.md")
410 .with_load_condition(LoadCondition::Keywords(vec![
411 "error".into(),
412 "result".into(),
413 "anyhow".into(),
414 ])),
415 ),
416 KnowledgeItem::new(
418 "tauri-expert",
419 "Tauri Expert",
420 "Expert Tauri v2 desktop app development with commands, plugins, capabilities, and frontend/backend IPC",
421 )
422 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
423 .with_triggers([
424 "tauri",
425 "desktop app",
426 "tauri v2",
427 "tauri command",
428 "tauri plugin",
429 "tauri::command",
430 "invoke handler",
431 "capabilities",
432 "webview2",
433 "ipc",
434 ])
435 .with_category("framework")
436 .with_content(include_str!("builtin/tauri_expert.md")),
437 KnowledgeItem::new(
439 "cli-expert",
440 "CLI Expert",
441 "Expert Rust CLI and TUI development with clap, ratatui, structured output, and terminal UX conventions",
442 )
443 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
444 .with_triggers([
445 "cli",
446 "clap",
447 "subcommand",
448 "ratatui",
449 "terminal",
450 "terminal ux",
451 "tui",
452 "command line",
453 "--json",
454 "--dry-run",
455 "no_color",
456 "assert_cmd",
457 ])
458 .with_category("tool")
459 .with_content(include_str!("builtin/cli_expert.md")),
460 KnowledgeItem::new(
462 "voice-expert",
463 "Voice Expert",
464 "Expert voice and audio pipelines with Whisper, whisper-rs, cpal, VAD, and speech-to-text",
465 )
466 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
467 .with_triggers([
468 "voice",
469 "whisper",
470 "whisper-rs",
471 "speech",
472 "speech-to-text",
473 "audio",
474 "microphone",
475 "transcription",
476 "stt",
477 "cpal",
478 "vad",
479 ])
480 .with_category("domain")
481 .with_content(include_str!("builtin/voice_expert.md")),
482 KnowledgeItem::new(
484 "mcp-expert",
485 "MCP Expert",
486 "Expert Model Context Protocol (2025-11-25) clients, servers, handshake flow, and tool/resource/prompt semantics",
487 )
488 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
489 .with_triggers([
490 "mcp",
491 "model context protocol",
492 "mcp client",
493 "tool calling",
494 "mcp server",
495 "tools/list",
496 "tools/call",
497 "resources/read",
498 "prompts/get",
499 "notifications/initialized",
500 "json-rpc",
501 ])
502 .with_category("protocol")
503 .with_content(include_str!("builtin/mcp_expert.md")),
504 KnowledgeItem::new(
506 "a2a-expert",
507 "A2A Expert",
508 "Expert Agent-to-Agent protocol design with Agent Cards, remote-agent delegation, streaming, and authentication",
509 )
510 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
511 .with_triggers([
512 "a2a",
513 "agent to agent",
514 "agent card",
515 "agent protocol",
516 "remote agent",
517 "task delegation",
518 "tasks/send",
519 "sendsubscribe",
520 "bearer auth",
521 "multi-agent",
522 ])
523 .with_category("protocol")
524 .with_content(include_str!("builtin/a2a_expert.md")),
525 KnowledgeItem::new(
527 "python-expert",
528 "Python Expert",
529 "Expert Python programming with modern Python 3.10+ patterns",
530 )
531 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
532 .with_triggers([
533 "python", "pip", "asyncio", "pydantic", "fastapi", "django", "flask", "pytest",
534 ])
535 .with_category("language")
536 .with_content(include_str!("builtin/python_expert.md")),
537 KnowledgeItem::new(
539 "javascript-expert",
540 "JavaScript Expert",
541 "Expert JavaScript programming with modern ES2023+ patterns",
542 )
543 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
544 .with_triggers([
545 "javascript",
546 "js",
547 "node",
548 "nodejs",
549 "npm",
550 "ecmascript",
551 "promise",
552 "event loop",
553 ])
554 .with_category("language")
555 .with_content(include_str!("builtin/javascript_expert.md")),
556 KnowledgeItem::new(
558 "typescript-expert",
559 "TypeScript Expert",
560 "Expert TypeScript programming with strict type system patterns",
561 )
562 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
563 .with_triggers([
564 "typescript",
565 "ts",
566 "tsconfig",
567 "type inference",
568 "generics typescript",
569 "zod",
570 ])
571 .with_category("language")
572 .with_content(include_str!("builtin/typescript_expert.md")),
573 KnowledgeItem::new(
575 "go-expert",
576 "Go Expert",
577 "Expert Go programming with idiomatic patterns and concurrency",
578 )
579 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
580 .with_triggers([
581 "go",
582 "golang",
583 "goroutine",
584 "channel",
585 "go module",
586 "defer",
587 "interface go",
588 ])
589 .with_category("language")
590 .with_content(include_str!("builtin/go_expert.md")),
591 KnowledgeItem::new(
593 "java-expert",
594 "Java Expert",
595 "Expert Java programming with modern Java 21+ and the JVM ecosystem",
596 )
597 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
598 .with_triggers([
599 "java",
600 "jvm",
601 "spring",
602 "maven",
603 "gradle",
604 "record java",
605 "stream api",
606 "virtual threads",
607 ])
608 .with_category("language")
609 .with_content(include_str!("builtin/java_expert.md")),
610 KnowledgeItem::new(
612 "cpp-expert",
613 "C++ Expert",
614 "Expert C++ programming with modern C++20/23 and RAII patterns",
615 )
616 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
617 .with_triggers([
618 "c++",
619 "cpp",
620 "cmake",
621 "raii",
622 "smart pointer",
623 "template",
624 "stl",
625 "concepts",
626 ])
627 .with_category("language")
628 .with_content(include_str!("builtin/cpp_expert.md")),
629 KnowledgeItem::new(
631 "csharp-expert",
632 "C# Expert",
633 "Expert C# programming with modern C# 12+ and .NET 8+",
634 )
635 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
636 .with_triggers([
637 "c#", "csharp", "dotnet", ".net", "asp.net", "linq", "nuget", "blazor",
638 ])
639 .with_category("language")
640 .with_content(include_str!("builtin/csharp_expert.md")),
641 KnowledgeItem::new(
643 "swift-expert",
644 "Swift Expert",
645 "Expert Swift programming with Swift 6, concurrency, and Apple platform development",
646 )
647 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
648 .with_triggers([
649 "swift",
650 "swiftui",
651 "ios",
652 "macos development",
653 "xcode",
654 "actor swift",
655 "combine",
656 "swiftpm",
657 ])
658 .with_category("language")
659 .with_content(include_str!("builtin/swift_expert.md")),
660 KnowledgeItem::new(
662 "kotlin-expert",
663 "Kotlin Expert",
664 "Expert Kotlin programming with coroutines and multiplatform development",
665 )
666 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
667 .with_triggers([
668 "kotlin",
669 "coroutines",
670 "ktor",
671 "android kotlin",
672 "kotlin multiplatform",
673 "flow kotlin",
674 ])
675 .with_category("language")
676 .with_content(include_str!("builtin/kotlin_expert.md")),
677 KnowledgeItem::new(
679 "ruby-expert",
680 "Ruby Expert",
681 "Expert Ruby programming with Ruby 3.x, Rails, and idiomatic patterns",
682 )
683 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
684 .with_triggers([
685 "ruby",
686 "rails",
687 "gem",
688 "bundler",
689 "rspec",
690 "active record",
691 "rake",
692 ])
693 .with_category("language")
694 .with_content(include_str!("builtin/ruby_expert.md")),
695 KnowledgeItem::new(
697 "php-expert",
698 "PHP Expert",
699 "Expert PHP programming with modern PHP 8.3+ and Composer ecosystem",
700 )
701 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
702 .with_triggers([
703 "php", "composer", "laravel", "symfony", "phpunit", "psr", "doctrine",
704 ])
705 .with_category("language")
706 .with_content(include_str!("builtin/php_expert.md")),
707 ];
708
709 items.extend(specialty_knowledge_items());
710 items.extend(anthropic_knowledge_work_plugins_sales_items());
711 items.extend(anthropic_skills_items());
712 items
713}
714
715fn specialty_knowledge_items() -> Vec<KnowledgeItem> {
716 vec![
717 specialty_item(
718 "analytics-expert",
719 "Analytics Expert",
720 "Metrics, experimentation, cohorts, and instrumentation for trustworthy product and business analytics",
721 "analytics",
722 [
723 "analytics",
724 "metric tree",
725 "instrumentation",
726 "experimentation",
727 "cohort analysis",
728 "retention",
729 ],
730 include_str!("builtin/analytics_expert.md"),
731 )
732 .with_priority(60),
733 specialty_item(
734 "science-expert",
735 "Science Expert",
736 "Hypotheses, study design, evidence quality, and reproducible scientific reasoning",
737 "science",
738 [
739 "science",
740 "scientific method",
741 "experimental design",
742 "evidence review",
743 "reproducibility",
744 "confounder",
745 ],
746 include_str!("builtin/science_expert.md"),
747 )
748 .with_priority(60),
749 specialty_item(
750 "math-expert",
751 "Math Expert",
752 "Modeling, optimization, derivations, estimation, and quantitative validation",
753 "math",
754 [
755 "math",
756 "mathematical modeling",
757 "optimization",
758 "derivation",
759 "estimation",
760 "proof",
761 ],
762 include_str!("builtin/math_expert.md"),
763 )
764 .with_priority(60),
765 specialty_item(
766 "marketing-expert",
767 "Marketing Expert",
768 "Positioning, messaging, go-to-market planning, campaign design, and growth strategy",
769 "marketing",
770 [
771 "marketing",
772 "positioning",
773 "messaging",
774 "go to market",
775 "campaign strategy",
776 "growth",
777 ],
778 include_str!("builtin/marketing_expert.md"),
779 )
780 .with_priority(60),
781 specialty_item(
782 "software-systems-expert",
783 "Software Systems Expert",
784 "Architecture, interfaces, observability, delivery, and operational reliability for production software systems",
785 "software",
786 [
787 "software systems",
788 "software architecture",
789 "system design",
790 "api contracts",
791 "observability",
792 "production reliability",
793 ],
794 include_str!("builtin/software_systems_expert.md"),
795 )
796 .with_priority(60),
797 specialty_item(
798 "robotics-expert",
799 "Robotics Expert",
800 "Perception, localization, controls, integration, and safety for robotic systems",
801 "robotics",
802 [
803 "robotics",
804 "perception",
805 "localization",
806 "controls",
807 "autonomy",
808 "robot safety",
809 ],
810 include_str!("builtin/robotics_expert.md"),
811 )
812 .with_priority(60),
813 specialty_item(
814 "mechanical-engineering-expert",
815 "Mechanical Engineering Expert",
816 "Loads, materials, tolerances, manufacturability, and reliability in mechanical systems",
817 "mechanical-engineering",
818 [
819 "mechanical engineering",
820 "loads",
821 "materials",
822 "tolerances",
823 "manufacturability",
824 "fatigue",
825 ],
826 include_str!("builtin/mechanical_engineering_expert.md"),
827 )
828 .with_priority(60),
829 specialty_item(
830 "electrical-engineering-expert",
831 "Electrical Engineering Expert",
832 "Power, signals, PCB interfaces, validation, and safe electrical system design",
833 "electrical-engineering",
834 [
835 "electrical engineering",
836 "power electronics",
837 "signal integrity",
838 "pcb",
839 "validation",
840 "sensor interface",
841 ],
842 include_str!("builtin/electrical_engineering_expert.md"),
843 )
844 .with_priority(60),
845 specialty_item(
846 "civil-engineering-expert",
847 "Civil Engineering Expert",
848 "Site design, drainage, structures, grading, and constructability for civil projects",
849 "civil-engineering",
850 [
851 "civil engineering",
852 "site grading",
853 "drainage",
854 "structures",
855 "constructability",
856 "foundation",
857 ],
858 include_str!("builtin/civil_engineering_expert.md"),
859 )
860 .with_priority(60),
861 specialty_item(
862 "chemical-engineering-expert",
863 "Chemical Engineering Expert",
864 "Mass balances, thermodynamics, kinetics, unit operations, and process safety",
865 "chemical-engineering",
866 [
867 "chemical engineering",
868 "mass balance",
869 "thermodynamics",
870 "reaction kinetics",
871 "unit operations",
872 "process safety",
873 ],
874 include_str!("builtin/chemical_engineering_expert.md"),
875 )
876 .with_priority(60),
877 specialty_item(
878 "aerospace-expert",
879 "Aerospace Expert",
880 "Mission architecture, flight dynamics, controls, verification, and aerospace systems reasoning",
881 "aerospace",
882 [
883 "aerospace",
884 "mission architecture",
885 "flight dynamics",
886 "guidance",
887 "control",
888 "verification",
889 ],
890 include_str!("builtin/aerospace_expert.md"),
891 )
892 .with_priority(60),
893 specialty_item(
894 "analytics-metrics-instrumentation",
895 "Analytics: Metrics & Instrumentation",
896 "Metric trees, event design, funnels, and trustworthy instrumentation",
897 "analytics",
898 [
899 "analytics",
900 "metrics",
901 "instrumentation",
902 "dashboard",
903 "funnel",
904 "event taxonomy",
905 ],
906 include_str!("builtin/analytics_metrics_instrumentation.md"),
907 ),
908 specialty_item(
909 "analytics-experimentation-insights",
910 "Analytics: Experimentation & Insights",
911 "Experiment design, readouts, cohort analysis, and decision-oriented insight generation",
912 "analytics",
913 [
914 "ab test",
915 "experiment analysis",
916 "cohort",
917 "segmentation",
918 "insight",
919 "measurement",
920 ],
921 include_str!("builtin/analytics_experimentation_insights.md"),
922 ),
923 specialty_item(
924 "science-hypothesis-design",
925 "Science: Hypothesis & Study Design",
926 "Scientific framing for hypotheses, variables, controls, and study design",
927 "science",
928 [
929 "science",
930 "hypothesis",
931 "study design",
932 "controls",
933 "variables",
934 "research design",
935 ],
936 include_str!("builtin/science_hypothesis_design.md"),
937 ),
938 specialty_item(
939 "science-evidence-review",
940 "Science: Evidence & Review",
941 "Evidence quality, literature review, interpretation, and reproducibility reasoning",
942 "science",
943 [
944 "evidence",
945 "literature review",
946 "reproducibility",
947 "bias",
948 "interpretation",
949 "scientific method",
950 ],
951 include_str!("builtin/science_evidence_review.md"),
952 ),
953 specialty_item(
954 "math-modeling-optimization",
955 "Math: Modeling & Optimization",
956 "Mathematical modeling, optimization setup, constraints, and sensitivity reasoning",
957 "math",
958 [
959 "math",
960 "modeling",
961 "optimization",
962 "constraints",
963 "sensitivity analysis",
964 "objective function",
965 ],
966 include_str!("builtin/math_modeling_optimization.md"),
967 ),
968 specialty_item(
969 "math-derivations-estimation",
970 "Math: Derivations & Estimation",
971 "Stepwise derivations, estimation, dimensional checks, and proof-oriented quantitative work",
972 "math",
973 [
974 "derivation",
975 "estimation",
976 "proof",
977 "units",
978 "order of magnitude",
979 "quantitative reasoning",
980 ],
981 include_str!("builtin/math_derivations_estimation.md"),
982 ),
983 specialty_item(
984 "marketing-positioning-messaging",
985 "Marketing: Positioning & Messaging",
986 "Audience definition, positioning, proof points, and message architecture",
987 "marketing",
988 [
989 "marketing",
990 "positioning",
991 "messaging",
992 "brand",
993 "icp",
994 "value proposition",
995 ],
996 include_str!("builtin/marketing_positioning_messaging.md"),
997 ),
998 specialty_item(
999 "marketing-campaign-growth",
1000 "Marketing: Campaigns & Growth",
1001 "Channel planning, launches, funnel experiments, and growth execution",
1002 "marketing",
1003 [
1004 "campaign",
1005 "growth",
1006 "launch",
1007 "content strategy",
1008 "channel mix",
1009 "go to market",
1010 ],
1011 include_str!("builtin/marketing_campaign_growth.md"),
1012 ),
1013 specialty_item(
1014 "software-architecture-interfaces",
1015 "Software: Architecture & Interfaces",
1016 "System boundaries, APIs, contracts, and production software structure",
1017 "software",
1018 [
1019 "software architecture",
1020 "system design",
1021 "api design",
1022 "interfaces",
1023 "data flow",
1024 "service boundaries",
1025 ],
1026 include_str!("builtin/software_architecture_interfaces.md"),
1027 ),
1028 specialty_item(
1029 "software-reliability-delivery",
1030 "Software: Reliability & Delivery",
1031 "Observability, rollout planning, test strategy, and operational reliability",
1032 "software",
1033 [
1034 "reliability",
1035 "observability",
1036 "testing strategy",
1037 "rollout",
1038 "incident prevention",
1039 "delivery",
1040 ],
1041 include_str!("builtin/software_reliability_delivery.md"),
1042 ),
1043 specialty_item(
1044 "robotics-perception-integration",
1045 "Robotics: Perception & Integration",
1046 "Sensors, localization, integration, calibration, and hardware/software interfaces",
1047 "robotics",
1048 [
1049 "robotics",
1050 "perception",
1051 "sensor fusion",
1052 "localization",
1053 "integration",
1054 "calibration",
1055 ],
1056 include_str!("builtin/robotics_perception_integration.md"),
1057 ),
1058 specialty_item(
1059 "robotics-controls-safety",
1060 "Robotics: Controls & Safety",
1061 "Planning, controls, fallback modes, latency, and safe robot behavior",
1062 "robotics",
1063 [
1064 "controls",
1065 "path planning",
1066 "safety envelope",
1067 "latency",
1068 "autonomy",
1069 "hardware in the loop",
1070 ],
1071 include_str!("builtin/robotics_controls_safety.md"),
1072 ),
1073 specialty_item(
1074 "mechanical-design-materials",
1075 "Mechanical Engineering: Design & Materials",
1076 "Loads, geometry, material choice, tolerances, and mechanical concept selection",
1077 "mechanical-engineering",
1078 [
1079 "mechanical engineering",
1080 "mechanical design",
1081 "materials",
1082 "loads",
1083 "tolerance",
1084 "stress",
1085 ],
1086 include_str!("builtin/mechanical_design_materials.md"),
1087 ),
1088 specialty_item(
1089 "mechanical-manufacturing-reliability",
1090 "Mechanical Engineering: Manufacturing & Reliability",
1091 "Manufacturability, fatigue, wear, maintenance, and failure-mode reasoning",
1092 "mechanical-engineering",
1093 [
1094 "manufacturability",
1095 "fatigue",
1096 "wear",
1097 "assembly",
1098 "maintenance",
1099 "failure modes",
1100 ],
1101 include_str!("builtin/mechanical_manufacturing_reliability.md"),
1102 ),
1103 specialty_item(
1104 "electrical-power-interfaces",
1105 "Electrical Engineering: Power & Interfaces",
1106 "Power architecture, electrical interfaces, grounding, and block-level partitioning",
1107 "electrical-engineering",
1108 [
1109 "electrical engineering",
1110 "power electronics",
1111 "interfaces",
1112 "grounding",
1113 "power budget",
1114 "block diagram",
1115 ],
1116 include_str!("builtin/electrical_power_interfaces.md"),
1117 ),
1118 specialty_item(
1119 "electrical-signals-validation",
1120 "Electrical Engineering: Signals & Validation",
1121 "Signal integrity, bring-up, measurement planning, and hardware validation",
1122 "electrical-engineering",
1123 [
1124 "signal integrity",
1125 "analog",
1126 "digital design",
1127 "pcb",
1128 "bring up",
1129 "hardware validation",
1130 ],
1131 include_str!("builtin/electrical_signals_validation.md"),
1132 ),
1133 specialty_item(
1134 "civil-site-drainage",
1135 "Civil Engineering: Site & Drainage",
1136 "Site constraints, grading, water movement, and civil layout reasoning",
1137 "civil-engineering",
1138 [
1139 "civil engineering",
1140 "site design",
1141 "drainage",
1142 "grading",
1143 "stormwater",
1144 "site constraints",
1145 ],
1146 include_str!("builtin/civil_site_drainage.md"),
1147 ),
1148 specialty_item(
1149 "civil-structures-constructability",
1150 "Civil Engineering: Structures & Constructability",
1151 "Load paths, constructability, sequencing, and code-aware infrastructure reasoning",
1152 "civil-engineering",
1153 [
1154 "structural load",
1155 "constructability",
1156 "sequencing",
1157 "code review",
1158 "geotechnical",
1159 "infrastructure",
1160 ],
1161 include_str!("builtin/civil_structures_constructability.md"),
1162 ),
1163 specialty_item(
1164 "chemical-balances-thermodynamics",
1165 "Chemical Engineering: Balances & Thermodynamics",
1166 "Mass/energy balances, operating windows, and thermodynamic process reasoning",
1167 "chemical-engineering",
1168 [
1169 "chemical engineering",
1170 "mass balance",
1171 "energy balance",
1172 "thermodynamics",
1173 "operating window",
1174 "process model",
1175 ],
1176 include_str!("builtin/chemical_balances_thermodynamics.md"),
1177 ),
1178 specialty_item(
1179 "chemical-kinetics-process-safety",
1180 "Chemical Engineering: Kinetics & Process Safety",
1181 "Reaction rates, separations, hazards, controllability, and process safety",
1182 "chemical-engineering",
1183 [
1184 "reaction kinetics",
1185 "separation process",
1186 "process safety",
1187 "hazard review",
1188 "controllability",
1189 "scale up",
1190 ],
1191 include_str!("builtin/chemical_kinetics_process_safety.md"),
1192 ),
1193 specialty_item(
1194 "aerospace-mission-architecture",
1195 "Aerospace: Mission & Architecture",
1196 "Mission profile, subsystem partitioning, budgets, and aerospace system tradeoffs",
1197 "aerospace",
1198 [
1199 "aerospace",
1200 "mission profile",
1201 "mass budget",
1202 "flight systems",
1203 "subsystems",
1204 "trade study",
1205 ],
1206 include_str!("builtin/aerospace_mission_architecture.md"),
1207 ),
1208 specialty_item(
1209 "aerospace-guidance-verification",
1210 "Aerospace: Guidance & Verification",
1211 "GNC, verification planning, safety margins, and qualification-oriented review",
1212 "aerospace",
1213 [
1214 "gnc",
1215 "verification",
1216 "qualification",
1217 "flight safety",
1218 "guidance",
1219 "avionics validation",
1220 ],
1221 include_str!("builtin/aerospace_guidance_verification.md"),
1222 ),
1223 ]
1224}
1225
1226fn specialty_item<const N: usize>(
1227 id: &'static str,
1228 name: &'static str,
1229 description: &'static str,
1230 category: &'static str,
1231 triggers: [&'static str; N],
1232 content: &'static str,
1233) -> KnowledgeItem {
1234 KnowledgeItem::new(id, name, description)
1235 .with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
1236 .with_triggers(triggers)
1237 .with_category(category)
1238 .with_content(content)
1239}
1240
1241fn with_apache_source(
1242 item: KnowledgeItem,
1243 source_repo: &'static str,
1244 source_path: &'static str,
1245 source_url: &'static str,
1246) -> KnowledgeItem {
1247 item.with_metadata(ORIGIN_KEY, ORIGIN_BUILTIN)
1248 .with_metadata("license", "Apache-2.0")
1249 .with_metadata("source_repo", source_repo)
1250 .with_metadata("source_path", source_path)
1251 .with_metadata("source_url", source_url)
1252}
1253
1254fn anthropic_knowledge_work_plugins_sales_items() -> Vec<KnowledgeItem> {
1255 const REPO: &str = "anthropics/knowledge-work-plugins";
1256
1257 vec![
1258 with_apache_source(
1260 KnowledgeItem::new(
1261 "sales-call-summary",
1262 "Sales: Call Summary",
1263 "Turn call notes/transcripts into action items + follow-up email",
1264 )
1265 .with_triggers([
1266 "sales",
1267 "call summary",
1268 "meeting notes",
1269 "transcript",
1270 "follow-up email",
1271 "action items",
1272 ])
1273 .with_category("sales")
1274 .with_priority(60)
1275 .with_content(include_str!("builtin/anthropics/sales_call_summary.md")),
1276 REPO,
1277 "sales/commands/call-summary.md",
1278 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/commands/call-summary.md",
1279 ),
1280 with_apache_source(
1281 KnowledgeItem::new(
1282 "sales-forecast",
1283 "Sales: Forecast",
1284 "Generate commit/upside forecast with best/likely/worst scenarios",
1285 )
1286 .with_triggers([
1287 "sales",
1288 "forecast",
1289 "quota",
1290 "pipeline",
1291 "commit",
1292 "upside",
1293 "coverage ratio",
1294 ])
1295 .with_category("sales")
1296 .with_priority(55)
1297 .with_content(include_str!("builtin/anthropics/sales_forecast.md")),
1298 REPO,
1299 "sales/commands/forecast.md",
1300 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/commands/forecast.md",
1301 ),
1302 with_apache_source(
1303 KnowledgeItem::new(
1304 "sales-pipeline-review",
1305 "Sales: Pipeline Review",
1306 "Pipeline health check + prioritization + weekly action plan",
1307 )
1308 .with_triggers([
1309 "sales",
1310 "pipeline review",
1311 "pipeline health",
1312 "stale deals",
1313 "close date",
1314 "next steps",
1315 ])
1316 .with_category("sales")
1317 .with_priority(55)
1318 .with_content(include_str!("builtin/anthropics/sales_pipeline_review.md")),
1319 REPO,
1320 "sales/commands/pipeline-review.md",
1321 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/commands/pipeline-review.md",
1322 ),
1323 with_apache_source(
1325 KnowledgeItem::new(
1326 "sales-account-research",
1327 "Sales: Account Research",
1328 "Research a company/person for outreach and meeting prep",
1329 )
1330 .with_triggers([
1331 "account research",
1332 "prospect research",
1333 "company research",
1334 "firmographics",
1335 "linkedin",
1336 "sales",
1337 ])
1338 .with_category("sales")
1339 .with_priority(50)
1340 .with_content(include_str!("builtin/anthropics/sales_account_research.md")),
1341 REPO,
1342 "sales/skills/account-research/SKILL.md",
1343 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/skills/account-research/SKILL.md",
1344 ),
1345 with_apache_source(
1346 KnowledgeItem::new(
1347 "sales-call-prep",
1348 "Sales: Call Prep",
1349 "Generate a call brief (agenda, questions, objections) for a prospect meeting",
1350 )
1351 .with_triggers([
1352 "call prep",
1353 "meeting prep",
1354 "discovery call",
1355 "demo",
1356 "agenda",
1357 "sales",
1358 ])
1359 .with_category("sales")
1360 .with_priority(50)
1361 .with_content(include_str!("builtin/anthropics/sales_call_prep.md")),
1362 REPO,
1363 "sales/skills/call-prep/SKILL.md",
1364 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/skills/call-prep/SKILL.md",
1365 ),
1366 with_apache_source(
1367 KnowledgeItem::new(
1368 "sales-competitive-intelligence",
1369 "Sales: Competitive Intelligence",
1370 "Create a competitor battlecard + positioning talk-tracks",
1371 )
1372 .with_triggers([
1373 "competitive intelligence",
1374 "battlecard",
1375 "competitor",
1376 "positioning",
1377 "win loss",
1378 "sales",
1379 ])
1380 .with_category("sales")
1381 .with_priority(45)
1382 .with_content(include_str!(
1383 "builtin/anthropics/sales_competitive_intelligence.md"
1384 )),
1385 REPO,
1386 "sales/skills/competitive-intelligence/SKILL.md",
1387 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/skills/competitive-intelligence/SKILL.md",
1388 ),
1389 with_apache_source(
1390 KnowledgeItem::new(
1391 "sales-create-an-asset",
1392 "Sales: Create an Asset",
1393 "Build customer-ready sales assets (one-pagers, decks, landing pages, workflows)",
1394 )
1395 .with_triggers([
1396 "create an asset",
1397 "sales asset",
1398 "one pager",
1399 "deck",
1400 "landing page",
1401 "workflow demo",
1402 ])
1403 .with_category("sales")
1404 .with_priority(45)
1405 .with_content(include_str!("builtin/anthropics/sales_create_an_asset.md")),
1406 REPO,
1407 "sales/skills/create-an-asset/SKILL.md",
1408 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/skills/create-an-asset/SKILL.md",
1409 ),
1410 with_apache_source(
1411 KnowledgeItem::new(
1412 "sales-daily-briefing",
1413 "Sales: Daily Briefing",
1414 "Daily prioritized plan (meetings, pipeline alerts, email priorities)",
1415 )
1416 .with_triggers([
1417 "daily briefing",
1418 "morning brief",
1419 "what should i do today",
1420 "sales",
1421 "pipeline alerts",
1422 ])
1423 .with_category("sales")
1424 .with_priority(40)
1425 .with_content(include_str!("builtin/anthropics/sales_daily_briefing.md")),
1426 REPO,
1427 "sales/skills/daily-briefing/SKILL.md",
1428 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/skills/daily-briefing/SKILL.md",
1429 ),
1430 with_apache_source(
1431 KnowledgeItem::new(
1432 "sales-draft-outreach",
1433 "Sales: Draft Outreach",
1434 "Research-first cold outreach (email + LinkedIn) with clear CTA",
1435 )
1436 .with_triggers([
1437 "draft outreach",
1438 "cold email",
1439 "linkedin message",
1440 "personalized outreach",
1441 "sales",
1442 ])
1443 .with_category("sales")
1444 .with_priority(45)
1445 .with_content(include_str!("builtin/anthropics/sales_draft_outreach.md")),
1446 REPO,
1447 "sales/skills/draft-outreach/SKILL.md",
1448 "https://raw.githubusercontent.com/anthropics/knowledge-work-plugins/main/sales/skills/draft-outreach/SKILL.md",
1449 ),
1450 ]
1451}
1452
1453fn anthropic_skills_items() -> Vec<KnowledgeItem> {
1454 const REPO: &str = "anthropics/skills";
1455
1456 vec![
1457 with_apache_source(
1458 KnowledgeItem::new(
1459 "anthropic-mcp-builder",
1460 "MCP Builder (Anthropic Skill)",
1461 "Guide to building high-quality MCP servers and tools",
1462 )
1463 .with_triggers([
1464 "mcp",
1465 "model context protocol",
1466 "mcp server",
1467 "tool schema",
1468 "tool design",
1469 "inspector",
1470 ])
1471 .with_category("protocol")
1472 .with_priority(55)
1473 .with_content(include_str!("builtin/anthropics/skill_mcp_builder.md")),
1474 REPO,
1475 "skills/mcp-builder/SKILL.md",
1476 "https://raw.githubusercontent.com/anthropics/skills/main/skills/mcp-builder/SKILL.md",
1477 ),
1478 with_apache_source(
1479 KnowledgeItem::new(
1480 "anthropic-frontend-design",
1481 "Frontend Design (Anthropic Skill)",
1482 "Guidelines for distinctive, production-grade UI implementation",
1483 )
1484 .with_triggers([
1485 "frontend design",
1486 "ui design",
1487 "css",
1488 "react",
1489 "component",
1490 "visual design",
1491 "typography",
1492 ])
1493 .with_category("design")
1494 .with_priority(50)
1495 .with_content(include_str!("builtin/anthropics/skill_frontend_design.md")),
1496 REPO,
1497 "skills/frontend-design/SKILL.md",
1498 "https://raw.githubusercontent.com/anthropics/skills/main/skills/frontend-design/SKILL.md",
1499 ),
1500 ]
1501}
1502
1503#[cfg(test)]
1504mod tests {
1505 use super::builtin_knowledge_items;
1506
1507 #[test]
1508 fn specialty_knowledge_items_are_registered() {
1509 let ids = builtin_knowledge_items()
1510 .into_iter()
1511 .map(|item| item.id)
1512 .collect::<std::collections::HashSet<_>>();
1513
1514 for expected_id in [
1515 "analytics-expert",
1516 "analytics-metrics-instrumentation",
1517 "analytics-experimentation-insights",
1518 "science-expert",
1519 "science-hypothesis-design",
1520 "science-evidence-review",
1521 "math-expert",
1522 "math-modeling-optimization",
1523 "math-derivations-estimation",
1524 "marketing-expert",
1525 "marketing-positioning-messaging",
1526 "marketing-campaign-growth",
1527 "software-systems-expert",
1528 "software-architecture-interfaces",
1529 "software-reliability-delivery",
1530 "robotics-expert",
1531 "robotics-perception-integration",
1532 "robotics-controls-safety",
1533 "mechanical-engineering-expert",
1534 "mechanical-design-materials",
1535 "mechanical-manufacturing-reliability",
1536 "electrical-engineering-expert",
1537 "electrical-power-interfaces",
1538 "electrical-signals-validation",
1539 "civil-engineering-expert",
1540 "civil-site-drainage",
1541 "civil-structures-constructability",
1542 "chemical-engineering-expert",
1543 "chemical-balances-thermodynamics",
1544 "chemical-kinetics-process-safety",
1545 "aerospace-expert",
1546 "aerospace-mission-architecture",
1547 "aerospace-guidance-verification",
1548 ] {
1549 assert!(ids.contains(expected_id), "missing {expected_id}");
1550 }
1551 }
1552}