Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 109 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
- [Watch Mode](#watch-mode)
- [Activating Watch Mode](#activating-watch-mode)
- [Example Use Cases](#example-use-cases)
- [Knowledge Base](#knowledge-base)
- [Creating Knowledge Bases](#creating-knowledge-bases)
- [Using Knowledge Bases](#using-knowledge-bases)
- [Auto-Loading Knowledge Bases](#auto-loading-knowledge-bases)
- [Squashing](#squashing)
- [What is Squashing?](#what-is-squashing)
- [Manual Squashing](#manual-squashing)
Expand Down Expand Up @@ -314,6 +318,97 @@ If you'd like to manage your context before reaching the automatic threshold, yo
TmuxAI » /squash
```

## Knowledge Base

The Knowledge Base feature allows you to create pre-defined context files in markdown format that can be loaded into TmuxAI's conversation context. This is useful for sharing common patterns, workflows, or project-specific information with the AI across sessions.

### Creating Knowledge Bases

Knowledge bases are markdown files stored in `~/.config/tmuxai/kb/`. To create one:

1. Create the knowledge base directory if it doesn't exist:
```bash
mkdir -p ~/.config/tmuxai/kb
```

2. Create a markdown file with your knowledge base content:
```bash
cat > ~/.config/tmuxai/kb/docker-workflows.md << 'EOF'
# Docker Workflows

## Common Commands
- Always use `docker compose` (not `docker-compose`)
- Prefer named volumes over bind mounts for databases
- Use `.env` files for environment-specific configuration

## Project Structure
- Development: `docker compose -f docker-compose.dev.yml up`
- Production: `docker compose -f docker-compose.prod.yml up -d`
EOF
```

### Using Knowledge Bases

Once created, you can load knowledge bases into your TmuxAI session:

```bash
# List available knowledge bases
TmuxAI » /kb
Available knowledge bases:
[ ] docker-workflows
[ ] git-conventions
[ ] testing-procedures

# Load a knowledge base
TmuxAI » /kb load docker-workflows
✓ Loaded knowledge base: docker-workflows (850 tokens)

# List again to see loaded status
TmuxAI » /kb
Available knowledge bases:
[✓] docker-workflows (850 tokens)
[ ] git-conventions
[ ] testing-procedures

Loaded: 1 KB(s), 850 tokens

# Unload a knowledge base
TmuxAI » /kb unload docker-workflows
✓ Unloaded knowledge base: docker-workflows

# Unload all knowledge bases
TmuxAI » /kb unload --all
✓ Unloaded all knowledge bases (2 KB(s))
```

You can also load knowledge bases directly from the command line when starting TmuxAI:

```bash
# Load single knowledge base
tmuxai --kb docker-workflows

# Load multiple knowledge bases (comma-separated)
tmuxai --kb docker-workflows,git-conventions
```

### Auto-Loading Knowledge Bases

You can configure knowledge bases to load automatically on startup by adding them to your `~/.config/tmuxai/config.yaml`:

```yaml
knowledge_base:
auto_load:
- docker-workflows
- git-conventions
# path: /custom/path # Optional: use custom KB directory
```

**Important Notes:**
- Loaded knowledge bases consume tokens from your context budget
- Use `/info` to see how many tokens your loaded KBs are using
- Knowledge bases are injected after the system prompt but before conversation history
- Unloading a KB removes it from future messages immediately

## Core Commands

| Command | Description |
Expand All @@ -324,8 +419,12 @@ TmuxAI » /squash
| `/config` | View current configuration settings |
| `/config set <key> <value>` | Override configuration for current session |
| `/squash` | Manually trigger context summarization |
| `/prepare [shell]` | Initialize Prepared Mode for the Exec Pane (e.g., bash, zsh) |
| `/prepare [shell]` | Initialize Prepared Mode for the Exec Pane (e.g., bash, zsh) |
| `/watch <description>` | Enable Watch Mode with specified goal |
| `/kb` | List available knowledge bases with loaded status |
| `/kb load <name>` | Load a knowledge base into conversation context |
| `/kb unload <name>` | Unload a specific knowledge base |
| `/kb unload --all` | Unload all knowledge bases |
| `/exit` | Exit TmuxAI |

## Command-Line Usage
Expand All @@ -343,6 +442,15 @@ You can start `tmuxai` with an initial message or task file from the command lin
tmuxai -f path/to/your_task.txt
```

- **Load Knowledge Bases:**
```sh
# Single knowledge base
tmuxai --kb docker-workflows

# Multiple knowledge bases
tmuxai --kb docker-workflows,git-conventions
```

## Configuration

The configuration can be managed through a YAML file, environment variables, or via runtime commands.
Expand Down
9 changes: 9 additions & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
var (
initMessage string
taskFileFlag string
kbFlag string
)

var rootCmd = &cobra.Command{
Expand Down Expand Up @@ -56,6 +57,13 @@ var rootCmd = &cobra.Command{
logger.Error("manager.NewManager failed: %v", err)
os.Exit(1)
}

// Load knowledge bases from CLI flag
if kbFlag != "" {
kbNames := strings.Split(kbFlag, ",")
mgr.LoadKBsFromCLI(kbNames)
}

if initMessage != "" {
logger.Info("Starting with initial subcommand: %s", initMessage)
}
Expand All @@ -69,6 +77,7 @@ var rootCmd = &cobra.Command{

func init() {
rootCmd.Flags().StringVarP(&taskFileFlag, "file", "f", "", "Read request from specified file")
rootCmd.Flags().StringVar(&kbFlag, "kb", "", "Comma-separated list of knowledge bases to load (e.g., --kb docker,git)")
rootCmd.Flags().BoolP("version", "v", false, "Print version information")
}

Expand Down
56 changes: 43 additions & 13 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ import (

// Config holds the application configuration
type Config struct {
Debug bool `mapstructure:"debug"`
MaxCaptureLines int `mapstructure:"max_capture_lines"`
MaxContextSize int `mapstructure:"max_context_size"`
WaitInterval int `mapstructure:"wait_interval"`
SendKeysConfirm bool `mapstructure:"send_keys_confirm"`
PasteMultilineConfirm bool `mapstructure:"paste_multiline_confirm"`
ExecConfirm bool `mapstructure:"exec_confirm"`
WhitelistPatterns []string `mapstructure:"whitelist_patterns"`
BlacklistPatterns []string `mapstructure:"blacklist_patterns"`
OpenRouter OpenRouterConfig `mapstructure:"openrouter"`
OpenAI OpenAIConfig `mapstructure:"openai"`
AzureOpenAI AzureOpenAIConfig `mapstructure:"azure_openai"`
Prompts PromptsConfig `mapstructure:"prompts"`
Debug bool `mapstructure:"debug"`
MaxCaptureLines int `mapstructure:"max_capture_lines"`
MaxContextSize int `mapstructure:"max_context_size"`
WaitInterval int `mapstructure:"wait_interval"`
SendKeysConfirm bool `mapstructure:"send_keys_confirm"`
PasteMultilineConfirm bool `mapstructure:"paste_multiline_confirm"`
ExecConfirm bool `mapstructure:"exec_confirm"`
WhitelistPatterns []string `mapstructure:"whitelist_patterns"`
BlacklistPatterns []string `mapstructure:"blacklist_patterns"`
OpenRouter OpenRouterConfig `mapstructure:"openrouter"`
OpenAI OpenAIConfig `mapstructure:"openai"`
AzureOpenAI AzureOpenAIConfig `mapstructure:"azure_openai"`
Prompts PromptsConfig `mapstructure:"prompts"`
KnowledgeBase KnowledgeBaseConfig `mapstructure:"knowledge_base"`
}

// OpenRouterConfig holds OpenRouter API configuration
Expand Down Expand Up @@ -57,6 +58,12 @@ type PromptsConfig struct {
Watch string `mapstructure:"watch"`
}

// KnowledgeBaseConfig holds knowledge base configuration
type KnowledgeBaseConfig struct {
AutoLoad []string `mapstructure:"auto_load"`
Path string `mapstructure:"path"`
}

// DefaultConfig returns a configuration with default values
func DefaultConfig() *Config {
return &Config{
Expand All @@ -81,6 +88,10 @@ func DefaultConfig() *Config {
BaseSystem: ``,
ChatAssistant: ``,
},
KnowledgeBase: KnowledgeBaseConfig{
AutoLoad: []string{},
Path: "",
},
}
}

Expand Down Expand Up @@ -174,6 +185,25 @@ func GetConfigFilePath(filename string) string {
return filepath.Join(configDir, filename)
}

// GetKBDir returns the path to the knowledge base directory
func GetKBDir() string {
// Try to load config to check for custom path
cfg, err := Load()
if err == nil && cfg.KnowledgeBase.Path != "" {
// Use custom path if specified
return cfg.KnowledgeBase.Path
}

// Default to ~/.config/tmuxai/kb/
configDir, _ := GetConfigDir()
kbDir := filepath.Join(configDir, "kb")

// Create KB directory if it doesn't exist
_ = os.MkdirAll(kbDir, 0o755)

return kbDir
}

func TryInferType(key, value string) any {
var typedValue any = value
// Only basic type inference for bool/int/string
Expand Down
26 changes: 26 additions & 0 deletions internal/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,32 @@ func (c *CLIInterface) newCompleter() *completion.CmdCompletionOrList2 {
return []string{"bash", "zsh", "fish"}, []string{"bash", "zsh", "fish"}
}
}

// Handle /kb subcommands
if len(field) > 0 && field[0] == "/kb" {
if len(field) == 1 || (len(field) == 2 && !strings.HasSuffix(field[1], " ")) {
return []string{"list", "load", "unload"}, []string{"list", "load", "unload"}
} else if (len(field) == 2 && field[1] == "load") || (len(field) >= 3 && field[1] == "load") {
// Get available knowledge bases for completion
kbs, err := c.manager.listKBs()
if err != nil {
return nil, nil
}
// Disable autocompletion when there's only one KB, bug with readline
if len(kbs) == 1 {
return nil, nil
}
return kbs, kbs
} else if (len(field) == 2 && field[1] == "unload") || (len(field) >= 3 && field[1] == "unload") {
// For unload, show loaded knowledge bases and --all option
var kbNames []string
for name := range c.manager.LoadedKBs {
kbNames = append(kbNames, name)
}
kbNames = append(kbNames, "--all")
return kbNames, kbNames
}
}
return nil, nil
},
}
Expand Down
Loading