claudetool/onstart: add codebase analysis tool and basic memory support

This is a preliminary approach. Big high level questions include:

* should we keep the multichoice tool prompting?
* should we push the list of quidance files or respond with them during codereview?
* should we use the list of docs and build files at all?
* are there other files we should hint (e.g. editor settings, something from aider, etc.)?

We should probably also blog about dear_llm.md to stop the endless proliferation of new files.

Co-Authored-By: sketch <hello@sketch.dev>
diff --git a/loop/agent.go b/loop/agent.go
index b3fd6c4..c103919 100644
--- a/loop/agent.go
+++ b/loop/agent.go
@@ -23,6 +23,7 @@
 	"sketch.dev/claudetool/bashkit"
 	"sketch.dev/claudetool/browse"
 	"sketch.dev/claudetool/codereview"
+	"sketch.dev/claudetool/onstart"
 	"sketch.dev/experiment"
 	"sketch.dev/llm"
 	"sketch.dev/llm/conversation"
@@ -296,6 +297,7 @@
 	gitRemoteAddr     string        // HTTP URL of the host git repo (only when under docker)
 	outsideHTTP       string        // base address of the outside webserver (only when under docker)
 	ready             chan struct{} // closed when the agent is initialized (only when under docker)
+	codebase          *onstart.Codebase
 	startedAt         time.Time
 	originalBudget    conversation.Budget
 	title             string
@@ -799,6 +801,15 @@
 		}
 		a.initialCommit = commitHash
 
+		if experiment.Enabled("memory") {
+			slog.Info("running codebase analysis")
+			codebase, err := onstart.AnalyzeCodebase(ctx, a.repoRoot)
+			if err != nil {
+				slog.Warn("failed to analyze codebase", "error", err)
+			}
+			a.codebase = codebase
+		}
+
 		llmCodeReview := codereview.NoLLMReview
 		if experiment.Enabled("llm_review") {
 			llmCodeReview = codereview.DoLLMReview
@@ -1808,6 +1819,7 @@
 	WorkingDir    string
 	RepoRoot      string
 	InitialCommit string
+	Codebase      *onstart.Codebase
 }
 
 // renderSystemPrompt renders the system prompt template.
@@ -1827,6 +1839,7 @@
 		WorkingDir:    a.workingDir,
 		RepoRoot:      a.repoRoot,
 		InitialCommit: a.initialCommit,
+		Codebase:      a.codebase,
 	}
 
 	tmpl, err := template.New("system").Parse(agentSystemPrompt)
@@ -1838,5 +1851,6 @@
 	if err != nil {
 		panic(fmt.Sprintf("failed to execute system prompt template: %v", err))
 	}
+	// fmt.Printf("system prompt: %s\n", buf.String())
 	return buf.String()
 }