Detailed changes
@@ -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)
}
@@ -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**:
@@ -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
@@ -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
@@ -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)
}
@@ -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("."),
"",
@@ -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,
})
},
},
@@ -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