From 4e40b4714644fd1bcb03fc3f0a74ca037f2189a5 Mon Sep 17 00:00:00 2001 From: Amolith Date: Thu, 13 Nov 2025 04:53:05 -0700 Subject: [PATCH] feat(config): default to AGENTS.md w/ new setting (#1403) --- internal/agent/prompts.go | 14 ++++++++++---- .../templates/{initialize.md => initialize.md.tpl} | 6 +++--- internal/config/config.go | 2 ++ internal/config/load.go | 3 +++ internal/config/load_test.go | 1 + internal/tui/components/chat/splash/splash.go | 9 +++++++-- .../tui/components/dialogs/commands/commands.go | 9 +++++++-- internal/tui/page/chat/chat.go | 2 +- 8 files changed, 34 insertions(+), 12 deletions(-) rename internal/agent/templates/{initialize.md => initialize.md.tpl} (85%) diff --git a/internal/agent/prompts.go b/internal/agent/prompts.go index 01be6561a9e74c71eba78991f942c77a68d8d879..577d32e4e274d9cb8274bd862af583208a613f08 100644 --- a/internal/agent/prompts.go +++ b/internal/agent/prompts.go @@ -1,9 +1,11 @@ package agent import ( + "context" _ "embed" "github.com/charmbracelet/crush/internal/agent/prompt" + "github.com/charmbracelet/crush/internal/config" ) //go:embed templates/coder.md.tpl @@ -12,8 +14,8 @@ var coderPromptTmpl []byte //go:embed templates/task.md.tpl var taskPromptTmpl []byte -//go:embed templates/initialize.md -var initializePrompt []byte +//go:embed templates/initialize.md.tpl +var initializePromptTmpl []byte func coderPrompt(opts ...prompt.Option) (*prompt.Prompt, error) { systemPrompt, err := prompt.NewPrompt("coder", string(coderPromptTmpl), opts...) @@ -31,6 +33,10 @@ func taskPrompt(opts ...prompt.Option) (*prompt.Prompt, error) { return systemPrompt, nil } -func InitializePrompt() string { - return string(initializePrompt) +func InitializePrompt(cfg config.Config) (string, error) { + systemPrompt, err := prompt.NewPrompt("initialize", string(initializePromptTmpl)) + if err != nil { + return "", err + } + return systemPrompt.Build(context.Background(), "", "", cfg) } diff --git a/internal/agent/templates/initialize.md b/internal/agent/templates/initialize.md.tpl similarity index 85% rename from internal/agent/templates/initialize.md rename to internal/agent/templates/initialize.md.tpl index 5eb1636c44094982ac1784aadeabdecb022a9dcc..1ca1a8132b07bc9d05efe32aaea04d050a1a1a2e 100644 --- a/internal/agent/templates/initialize.md +++ b/internal/agent/templates/initialize.md.tpl @@ -1,6 +1,6 @@ -Analyze this codebase and create/update **CRUSH.md** to help future agents work effectively in this repository. +Analyze this codebase and create/update **{{.Config.Options.InitializeAs}}** to help future agents work effectively in this repository. -**First**: Check if directory is empty or contains only config files. If so, stop and say "Directory appears empty or only contains config. Add source code first, then run this command to generate CRUSH.md." +**First**: Check if directory is empty or contains only config files. If so, stop and say "Directory appears empty or only contains config. Add source code first, then run this command to generate {{.Config.Options.InitializeAs}}." **Goal**: Document what an agent needs to know to work in this codebase - commands, patterns, conventions, gotchas. @@ -11,7 +11,7 @@ Analyze this codebase and create/update **CRUSH.md** to help future agents work 3. Identify project type from config files and directory structure 4. Find build/test/lint commands from config files, scripts, Makefiles, or CI configs 5. Read representative source files to understand code patterns -6. If CRUSH.md exists, read and improve it +6. If {{.Config.Options.InitializeAs}} exists, read and improve it **Content to include**: diff --git a/internal/config/config.go b/internal/config/config.go index 9d49c554034a59a6f549660297d2c59e10536c8b..2adc45f050b46afb8788042035531c032159926e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,6 +21,7 @@ import ( const ( appName = "crush" defaultDataDirectory = ".crush" + defaultInitializeAs = "AGENTS.md" ) var defaultContextPaths = []string{ @@ -201,6 +202,7 @@ type Options struct { DisableProviderAutoUpdate bool `json:"disable_provider_auto_update,omitempty" jsonschema:"description=Disable providers auto-update,default=false"` Attribution *Attribution `json:"attribution,omitempty" jsonschema:"description=Attribution settings for generated content"` DisableMetrics bool `json:"disable_metrics,omitempty" jsonschema:"description=Disable sending metrics,default=false"` + InitializeAs string `json:"initialize_as,omitempty" jsonschema:"description=Name of the context file to create/update during project initialization,default=AGENTS.md,example=AGENTS.md,example=CRUSH.md,example=CLAUDE.md,example=docs/LLMs.md"` } type MCPs map[string]MCPConfig diff --git a/internal/config/load.go b/internal/config/load.go index 77c9377445acadbdeeb49b97996f9a45be0b6dc3..a766f838225692d0c4f732043f04613899e35a40 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -364,6 +364,9 @@ func (c *Config) setDefaults(workingDir, dataDir string) { c.Options.Attribution.TrailerStyle = TrailerStyleCoAuthoredBy } } + if c.Options.InitializeAs == "" { + c.Options.InitializeAs = defaultInitializeAs + } } // applyLSPDefaults applies default values from powernap to LSP configurations diff --git a/internal/config/load_test.go b/internal/config/load_test.go index 2882e4c521a31b2131fb2b3614589925ce8faef8..af50daad6719249815927cad70cb4900d2bd12f6 100644 --- a/internal/config/load_test.go +++ b/internal/config/load_test.go @@ -50,6 +50,7 @@ func TestConfig_setDefaults(t *testing.T) { require.NotNil(t, cfg.LSP) require.NotNil(t, cfg.MCP) require.Equal(t, filepath.Join("/tmp", ".crush"), cfg.Options.DataDirectory) + require.Equal(t, "AGENTS.md", cfg.Options.InitializeAs) for _, path := range defaultContextPaths { require.Contains(t, cfg.Options.ContextPaths, path) } diff --git a/internal/tui/components/chat/splash/splash.go b/internal/tui/components/chat/splash/splash.go index 3b995ab22ded328c49bda36714438c7d4c7b39eb..78d12a2d228ac4117a145f20641d7954482bfc3e 100644 --- a/internal/tui/components/chat/splash/splash.go +++ b/internal/tui/components/chat/splash/splash.go @@ -331,10 +331,14 @@ func (s *splashCmp) initializeProject() tea.Cmd { cmds = append(cmds, util.CmdHandler(OnboardingCompleteMsg{})) if !s.selectedNo { + initPrompt, err := agent.InitializePrompt(*config.Get()) + if err != nil { + return util.ReportError(err) + } cmds = append(cmds, util.CmdHandler(chat.SessionClearedMsg{}), util.CmdHandler(chat.SendMsg{ - Text: agent.InitializePrompt(), + Text: initPrompt, }), ) } @@ -458,6 +462,7 @@ func (s *splashCmp) View() string { bodyStyle := t.S().Base.Foreground(t.FgMuted) shortcutStyle := t.S().Base.Foreground(t.Success) + initFile := config.Get().Options.InitializeAs initText := lipgloss.JoinVertical( lipgloss.Left, titleStyle.Render("Would you like to initialize this project?"), @@ -465,7 +470,7 @@ func (s *splashCmp) View() string { pathStyle.Render(s.cwd()), "", bodyStyle.Render("When I initialize your codebase I examine the project and put the"), - bodyStyle.Render("result into a CRUSH.md file which serves as general context."), + bodyStyle.Render(fmt.Sprintf("result into an %s file which serves as general context.", initFile)), "", bodyStyle.Render("You can also initialize anytime via ")+shortcutStyle.Render("ctrl+p")+bodyStyle.Render("."), "", diff --git a/internal/tui/components/dialogs/commands/commands.go b/internal/tui/components/dialogs/commands/commands.go index dfe1cd6ade60da7494eab99ede1f104aa045141a..1e6bfd9fc0791ba45b8c76edc3ca745e0fa53528 100644 --- a/internal/tui/components/dialogs/commands/commands.go +++ b/internal/tui/components/dialogs/commands/commands.go @@ -1,6 +1,7 @@ package commands import ( + "fmt" "os" "slices" "strings" @@ -454,10 +455,14 @@ func (c *commandDialogCmp) defaultCommands() []Command { { ID: "init", Title: "Initialize Project", - Description: "Create/Update the CRUSH.md memory file", + Description: fmt.Sprintf("Create/Update the %s memory file", config.Get().Options.InitializeAs), Handler: func(cmd Command) tea.Cmd { + initPrompt, err := agent.InitializePrompt(*config.Get()) + if err != nil { + return util.ReportError(err) + } return util.CmdHandler(chat.SendMsg{ - Text: agent.InitializePrompt(), + Text: initPrompt, }) }, }, diff --git a/internal/tui/page/chat/chat.go b/internal/tui/page/chat/chat.go index 3d9d550097635380ba9e5f7a9002a8cf69a61d91..f951de8677271dfbf034377afaa492f0d8824889 100644 --- a/internal/tui/page/chat/chat.go +++ b/internal/tui/page/chat/chat.go @@ -144,7 +144,7 @@ func (p *chatPage) Init() tea.Cmd { p.isOnboarding = true p.splashFullScreen = true } else if b, _ := config.ProjectNeedsInitialization(); b { - // Project needs CRUSH.md initialization + // Project needs context initialization p.splash.SetProjectInit(true) p.isProjectInit = true p.splashFullScreen = true