feat(config): Add multi-agent support with pluggable registry
Implements agent abstraction layer to support multiple AI coding agents. Built-in presets (E2E tested): - Claude Code (default) - Gemini CLI - OpenAI Codex Key changes: - Add AgentRegistry with built-in presets and custom agent support - Add TownSettings with default_agent and custom agents map - Add Agent field to RigSettings for per-rig agent selection - Update ResolveAgentConfig for hierarchical config resolution - Update spawn paths to use configured agent instead of hardcoded claude Configuration hierarchy (first match wins): 1. Rig's Runtime config (backwards compat) 2. Rig's Agent -> custom agents -> built-in presets 3. Town's default_agent setting 4. Fallback to Claude Additional agents (aider, opencode, etc.) can be added via config file: settings/agents.json Addresses Issue #10: Agent Agnostic Engine with Multi-provider support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -183,10 +183,11 @@ func runCrewAt(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// Check if we're already in the target session
|
||||
if isInTmuxSession(sessionID) {
|
||||
// We're in the session at a shell prompt - just start Claude directly
|
||||
// Pass "gt prime" as initial prompt so Claude loads context immediately
|
||||
fmt.Printf("Starting Claude in current session...\n")
|
||||
return execClaude("gt prime")
|
||||
// We're in the session at a shell prompt - just start the agent directly
|
||||
// Pass "gt prime" as initial prompt so it loads context immediately
|
||||
agentCfg := config.ResolveAgentConfig(townRoot, r.Path)
|
||||
fmt.Printf("Starting %s in current session...\n", agentCfg.Command)
|
||||
return execAgent(agentCfg, "gt prime")
|
||||
}
|
||||
|
||||
// If inside tmux (but different session), don't switch - just inform user
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/steveyegge/gastown/internal/config"
|
||||
"github.com/steveyegge/gastown/internal/constants"
|
||||
"github.com/steveyegge/gastown/internal/crew"
|
||||
"github.com/steveyegge/gastown/internal/git"
|
||||
@@ -147,21 +148,26 @@ func isShellCommand(cmd string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// execClaude execs claude, replacing the current process.
|
||||
// Used when we're already in the target session and just need to start Claude.
|
||||
// If prompt is provided, it's passed as the initial prompt to Claude.
|
||||
func execClaude(prompt string) error {
|
||||
claudePath, err := exec.LookPath("claude")
|
||||
if err != nil {
|
||||
return fmt.Errorf("claude not found: %w", err)
|
||||
// execAgent execs the configured agent, replacing the current process.
|
||||
// Used when we're already in the target session and just need to start the agent.
|
||||
// If prompt is provided, it's passed as the initial prompt.
|
||||
func execAgent(cfg *config.RuntimeConfig, prompt string) error {
|
||||
if cfg == nil {
|
||||
cfg = config.DefaultRuntimeConfig()
|
||||
}
|
||||
|
||||
// exec replaces current process with claude
|
||||
args := []string{"claude", "--dangerously-skip-permissions"}
|
||||
agentPath, err := exec.LookPath(cfg.Command)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s not found: %w", cfg.Command, err)
|
||||
}
|
||||
|
||||
// exec replaces current process with agent
|
||||
// args[0] must be the command name (convention for exec)
|
||||
args := append([]string{cfg.Command}, cfg.Args...)
|
||||
if prompt != "" {
|
||||
args = append(args, prompt)
|
||||
}
|
||||
return syscall.Exec(claudePath, args, os.Environ())
|
||||
return syscall.Exec(agentPath, args, os.Environ())
|
||||
}
|
||||
|
||||
// isInTmuxSession checks if we're currently inside the target tmux session.
|
||||
|
||||
@@ -122,7 +122,9 @@ func SpawnPolecatForSling(rigName string, opts SlingSpawnOptions) (*SpawnedPolec
|
||||
fmt.Printf("Polecat created. Agent must be started manually.\n\n")
|
||||
fmt.Printf("To start the agent:\n")
|
||||
fmt.Printf(" cd %s\n", polecatObj.ClonePath)
|
||||
fmt.Printf(" claude --dangerously-skip-permissions\n\n")
|
||||
// Use rig's configured agent command
|
||||
agentCmd := config.ResolveAgentConfig(townRoot, r.Path).BuildCommand()
|
||||
fmt.Printf(" %s\n\n", agentCmd)
|
||||
fmt.Printf("Agent will discover work via gt prime on startup.\n")
|
||||
|
||||
return &SpawnedPolecatInfo{
|
||||
|
||||
Reference in New Issue
Block a user