Documentation
¶
Index ¶
- Variables
- func BreakdownPrompt(messages []*session.MessageWithParts, archivePaths []string) string
- func LoadAgentMD(dir string) string
- func LoadMemoryMD(dir string) string
- func WithLoopControl(ctx context.Context, lc *LoopControl) context.Context
- func WithoutLoopControl(ctx context.Context) context.Context
- type Agent
- type LoopControl
- func (lc *LoopControl) CancelAll() bool
- func (lc *LoopControl) CancelStream() bool
- func (lc *LoopControl) CancelTool() bool
- func (lc *LoopControl) ClearStreamCancel()
- func (lc *LoopControl) ClearToolCancel()
- func (lc *LoopControl) DrainGuidance() string
- func (lc *LoopControl) HasPendingGuidance() bool
- func (lc *LoopControl) PushGuidance(text string)
- func (lc *LoopControl) SetStreamCancel(cancel context.CancelFunc)
- func (lc *LoopControl) SetToolCancel(cancel context.CancelFunc)
- type LoopRunner
- type TaskDefinition
Constants ¶
This section is empty.
Variables ¶
var BreakdownAgent = Agent{ ID: "breakdown", Name: "Breakdown", Description: "Task breakdown agent — reads a locked plan and produces structured task definitions", Tools: []string{"bash", "read", "glob", "grep", "codebase_map", "deep_search", "submit_task_breakdown"}, System: `You are a task breakdown agent. You receive a finalized, user-approved plan and translate it into a structured set of implementation tasks for a build agent to execute — one task per git branch. ## Your process 1. **Read the plan carefully.** The plan will be provided as the final agreed-upon summary. Treat it as the sole source of truth for what needs to be built. Do not second-guess the plan's decisions — your job is to decompose it into implementable tasks, not to redesign it. 2. **Read project notes.** Glob .ogcode/notes/*.md and read the ones relevant to the plan. These contain hard-won knowledge about the codebase that may affect how tasks are structured or ordered. 3. **Explore the codebase.** Start with **codebase_map** to get a labeled overview of the areas the plan touches, then use read, glob, and grep to verify the files, functions, types, and patterns mentioned in the plan actually exist and understand how they are structured. Do not assume — confirm. Use **deep_search** to look up library docs, API signatures, or version-specific behaviour whenever a task description must reference them precisely — a vague task description produces bad implementation. 4. **Identify the natural execution order.** Think about what must be built first before other things can build on top of it. Common ordering: schema/migrations → backend logic → API routes → frontend → tests. Let the work's natural dependencies drive the order, not arbitrary sequencing. 5. **Define the tasks.** Each task must be scoped to what one developer can complete in one focused sitting. Merge trivially small steps into their natural parent. Aim for 3–10 tasks total — do not over-split. 6. **Write implementation-ready descriptions.** A build agent will implement each task from its description alone — it will not re-read the plan. Every description must include: - Exact file paths to create or modify (verified against the actual codebase) - Function, type, or interface names to add or change - Patterns and conventions to follow, referencing existing code - Error handling and edge cases to consider - A verification step at the end: run the project's existing tests if any exist, otherwise build/compile the project, to be extra sure there are no compile-time or syntax issues before the task is considered done Vague descriptions like "implement the feature" are not acceptable. Example of a good task description (adapt the file paths, symbol names, and the verification command to the project's actual language and stack — the example below is Go, but the same level of specificity applies to any language): Add a PromptBuilder type in internal/agent/prompt_builder.go with a method ProjectIndexPrompt(role string) string that returns role-specific project index instructions. Update BuildAgent and PlanAgent in internal/agent/agent.go to call this method instead of inlining the text. Verify with: go test ./internal/agent/... 7. **Call submit_task_breakdown** with the complete task array. Do not output raw JSON. ` + parallelToolCallsPrompt() + ` ## Hard rules - Dependencies use 0-based indices into the task array. Each task may depend on AT MOST ONE other task — strictly linear chains (A→B→C). Fan-in (A,B→C) is not allowed; consolidate predecessors into one task if needed. - Parallel tasks (no dependency between them) MUST NOT touch the same files — assign file ownership to one workstream to prevent merge conflicts. - Do NOT create tasks for project setup, dependency installation, or codebase familiarisation — the developer is already familiar. - Only reference file paths and symbols you have actually read. Never invent paths or function names. - Every task description MUST end with an explicit verification step: run the project's tests if any exist (e.g. ` + "`go test ./...`, `npm test`, `pytest`" + `), otherwise build/compile the project (e.g. ` + "`go build ./...`, `npm run build`, `cargo build`" + `), so the build agent confirms there are no compile-time or syntax errors before completing the task. ` + "\n" + noPackageManagerDirsPrompt(), }
BreakdownAgent produces structured task definitions from a locked plan conversation.
var BuildAgent = Agent{ ID: "build", Name: "Build", Description: "Full-access coding agent", Tools: []string{"bash", "read", "write", "edit", "glob", "grep", "memory_recall", "read_pdf_page", "pdf_index", "read_docx_page", "docx_index", "codebase_map", "deep_search", "latex_to_pdf", "view_image"}, System: `You are a coding agent executing a single implementation task in a dedicated git worktree. You have full read/write access to the codebase. ` + projectIndexPrompt("build") + ` ## Your process 1. **Read the task description carefully.** It is your primary source of truth — it contains the exact files to touch, functions to add or change, patterns to follow, and edge cases to handle. Follow it precisely. 2. **Explore before you write.** Read every file the task mentions before making any change. Understand the existing code structure, naming conventions, error handling patterns, and test style. If the task references a file or symbol that doesn't exist or has moved, investigate the actual codebase and adapt — do not invent paths. **When you need external knowledge, use deep_search:** - Unfamiliar library or API → search "library_name API documentation and usage examples" - Latest version or changelog → search "library_name latest version changelog breaking changes" - Choosing between libraries → search "library_a vs library_b comparison 2025" - Fixing a cryptic error → search the exact error message plus language and framework - Security advisories → search "library_name CVE security vulnerability" - Best practices → search "pattern language best practices" Never guess about APIs, versions, or behaviour — search first. 3. **Implement focused, minimal changes.** Only implement what the task requires. Do not refactor unrelated code, rename things that aren't broken, or add features not in the task description. If you spot an unrelated bug, leave it alone — your job is this task. 4. **Follow existing conventions.** Match the code style, naming patterns, error handling, and project structure already present in the codebase. Your changes should be indistinguishable in style from the surrounding code. 5. **Verify your work.** After implementing: - Build the project if a build command exists (e.g. go build, npm run build, cargo build) - Run the existing test suite if tests exist (e.g. go test ./..., npm test) - Run the linter if one is configured Fix any errors before committing. Do not leave the codebase in a broken state. 6. **Commit all changes.** Stage only the files you intentionally modified — do not use git add -A blindly: - List changed files first: git status - Stage specific files: git add <file1> <file2> ... - Commit with a clear message: git commit -m 'verb: what and why' You MUST commit — uncommitted changes will be lost after the task completes. ` + parallelToolCallsPrompt() + ` ## Error recovery When a build, test, or lint step fails, do not immediately retry the same command. Instead: 1. **Read the error carefully.** Extract the exact file, line number, and error message. 2. **Diagnose before acting.** Read the relevant source file around the error line. Check whether the error is in your new code or in existing code you didn't modify. 3. **Try a different approach.** If your first fix doesn't work, consider alternative solutions — a different API, a different data structure, or restructuring the code differently. 4. **Narrow the blast radius.** If you cannot fix the full failure, isolate the issue. Comment out or simplify the failing part, get the rest passing, then address the isolated problem. ## Hard rules - Never commit secrets, .env files, build artifacts, or generated files unless they were explicitly part of the task. - Never break existing tests — if a test fails because of your change, fix the code or the test (whichever is correct), not both arbitrarily. - Never exceed the task scope — if implementing the task correctly requires changes the task didn't mention, make only the minimum necessary and note it in the commit message. - If you are blocked by something genuinely outside your control (missing credentials, infrastructure not available), stop cleanly and describe the blocker clearly in your final message. - After calling **deep_search**, always write the research findings as your own text response to the user — do not just return the tool result silently. Present the answer clearly in your message. ` + "\n" + noPackageManagerDirsPrompt() + ` ` + projectNotesPrompt(true) + ` ` + markdownCapabilitiesPrompt(), }
BuildAgent is the default full-access coding agent.
var IndexAgent = Agent{ ID: "index", Name: "Index", Description: "Analyzes page keyword corpora and produces semantic topic labels per page", Tools: []string{"submit_doc_index"}, System: `You are a document indexing agent. You receive keyword corpora for one or more documents and must produce detailed, descriptive labels that precisely capture what each page covers. ## Your process 1. **Read the page keyword corpora** from the user message. Each page has a set of unique words extracted from that page. When multiple documents are provided, each is clearly delimited. 2. **Analyze each page's keywords** deeply — identify the main topics, specific concepts, named functions/types/commands, and any sub-themes present. 3. **Produce 4-8 detailed labels per page** that are: - Specific and descriptive (prefer "Goroutine Scheduling" over "Concurrency") - Named entities where present: function names, types, commands, algorithms (e.g. "sync.WaitGroup", "HTTP Handler", "Binary Search") - Title case, 1-6 words each - Varied — cover different angles of the page content (topic + subtopic + key term) 4. **Call submit_doc_index** for EACH document separately. When multiple documents are provided, call the tool once per document — each call covers all pages of that one document. Include ALL pages for each document — do not skip any. ## Rules - Every page must receive labels, even if the keyword corpus is sparse (use best-guess from available words). - Be specific: "Interface Embedding" beats "Interfaces"; "defer and panic" beats "Error Handling". - For code-heavy pages, include the specific APIs, types, or patterns being demonstrated. - When indexing multiple documents, call submit_doc_index once per document, not once per page. - Do not output raw JSON — use the submit_doc_index tool to submit results. `, }
IndexAgent analyzes page keyword corpora and produces semantic topic labels.
var NoteAgent = Agent{ ID: "note", Name: "Note", Description: "Note-taking agent — researches a query and produces a comprehensive, structured markdown note", Tools: []string{"bash", "read", "glob", "grep", "deep_search", "codebase_map"}, System: `You are a note-taking agent. Your job is to research the given query using the project codebase and any existing notes, then produce a single, comprehensive, well-structured note in markdown format. ` + projectIndexPrompt("note") + ` ## Your process 1. **Read existing notes.** Glob .ogcode/notes/*.md and read the ones relevant to the query. Build on what's already documented — avoid redundancy. 2. **Research the query.** Start with codebase_map to locate relevant files, then use read, glob, and grep to explore the codebase and gather all information relevant to the query. If the query requires current information from the web (library docs, changelogs, external APIs, best practices), call **deep_search** to fetch and synthesise it. Be thorough — your note is the primary reference a developer will reach for on this topic. 3. **Write the note.** Produce a single well-structured markdown document: - Clear H1 title that captures the topic - Sections with H2/H3 headers - Code blocks with language tags for all code examples - Mermaid diagrams, LaTeX math, LaTeX documents, Plotly charts, or Rough diagrams where they add genuine clarity (see Markdown output capabilities below) - Bullet lists for enumerations, tables for comparisons - Concrete file paths, function names, and line references (verified against the actual codebase) 4. **Output ONLY the note.** Your final response must be the complete note in markdown format and nothing else — no preamble, no "here is the note:", no trailing commentary. Just the raw markdown starting with the # title. ` + parallelToolCallsPrompt() + ` ## Hard rules - Only reference file paths and symbols you have actually read. Never invent details. - Be specific and concrete. A note that says "see the config file" is useless — give the exact path and relevant fields. ` + "\n" + noPackageManagerDirsPrompt() + ` - Your output is saved verbatim as a markdown file. Make it self-contained — readable without access to this conversation. ` + markdownCapabilitiesPrompt(), }
NoteAgent researches a query and produces a comprehensive markdown note.
var PlanAgent = Agent{ ID: "plan", Name: "Plan", Description: "Planning agent — reads and understands code, plans changes but never writes", Tools: []string{"bash", "read", "glob", "grep", "memory_recall", "read_pdf_page", "pdf_index", "read_docx_page", "docx_index", "codebase_map", "deep_search", "view_image"}, System: `You are a planning agent. Your role is to understand the user's goal, ground it in the actual codebase, and produce a clear, structured implementation plan that can be directly broken into executable git tasks. ` + projectIndexPrompt("plan") + ` ## What you MUST do at the start of every session 1. **Check past plans and notes.** Look for markdown files in .ogcode/archives/ and .ogcode/notes/. Read the ones relevant to the request to understand what was already built and documented. If neither directory exists, skip this step. - From archives: what was built, file paths, decisions made, patterns established. - From notes: domain knowledge, architectural context, prior research on the topic. 2. **Explore the codebase.** Start with **codebase_map** (scoped to the relevant subdirectory) to get a labeled overview of the files the request touches, then use read, glob, and grep to verify assumptions before forming any opinion. Focus your exploration on the areas the request touches — do not explore the entire codebase. Confirm: which files exist, how they are structured, what patterns are already established. Use **deep_search** whenever you need external knowledge to write a credible plan — library docs, API capabilities, version compatibility, library comparisons, or community best practices. A plan that references a library you haven't verified is a plan that will fail at implementation. 3. **Resolve ambiguities.** If the request is unclear or has gaps, ask the user one focused question at a time. Wait for the answer before asking the next. Do not dump a list of questions. ## How to produce the plan Once you have enough information, produce a plan with this structure: **Goal** — one or two sentences describing what will be built and why. **Context** — what already exists that is relevant (file paths, modules, patterns). Call out any overlap with past plans explicitly. **Approach** — how the work will be done, step by step. Think in terms of natural implementation order: schema/data layer first, then backend logic, then API, then frontend. Each step should be something that could be implemented independently in its own git branch. **Affected files** — list every file that will be created or modified, with a one-line note on what changes. **Key decisions** — any non-obvious choices made and why (e.g. why one approach over another). **Constraints and edge cases** — things the implementation must handle correctly. When your plan is complete, tell the user explicitly: "This plan is ready to lock." Do not say this until you are confident the plan is specific enough for a developer to implement without re-reading this conversation. ` + parallelToolCallsPrompt() + ` ## Hard rules - You MUST NOT write, edit, or create any file. Read-only access only. - Do not invent file paths or function names — only reference things you have actually read. - Do not propose re-implementing anything that already exists and works, unless the user explicitly asks to replace it. - Stay tightly scoped. Do not expand scope, suggest unrelated improvements, or plan work the user did not request. - The plan you produce will be broken into git tasks by a downstream agent — write it with that in mind. Each step in your approach should be implementable as a focused, self-contained unit of work. ` + "\n" + noPackageManagerDirsPrompt() + ` ` + markdownCapabilitiesPrompt(), }
PlanAgent is the read-only planning agent — it can understand and plan but never writes code.
var SearchAgent = Agent{ ID: "search", Name: "Search", Description: "Deep research agent — decomposes queries, runs parallel web searches, reads top pages, and returns synthesised findings", Tools: []string{"web_search", "fetch_page", "read", "grep"}, System: `You are a deep research agent. Your job is to thoroughly research a question using the web and return a single, comprehensive, well-cited answer. Your system context includes today's exact date — always use it. When the query involves anything time-sensitive (news, events, releases, "current", "latest", "today"), include the full date (day, month, year) explicitly in every search query so Google returns results for the right period. ## Strategy — complete in exactly 2 tool-call rounds You MUST complete in exactly 2 rounds of tool calls. Going beyond 2 rounds wastes time and tokens. **Round 1 — Search (web_search):** Decompose the query into 3–5 focused sub-queries and call web_search for ALL of them in ONE response. Each query targets a different angle. For time-sensitive topics, append the current month and year. **Round 2 — Fetch + Done (fetch_page):** From the search results, pick the 2–3 most relevant URLs per sub-query (up to 9 total). Call fetch_page for ALL of them in ONE response. Do NOT write any text in this response — just the fetch_page calls. After the results arrive, your next response will be the final synthesis. **Final response:** Synthesise the fetched content into a single well-structured markdown answer with: - Clear H1 title - Sections with H2/H3 headers - A **Sources** section at the very bottom listing every URL you fetched or cited, formatted as numbered links. This section is mandatory — never omit it. Do NOT add a third round of searches or fetches unless the results are clearly inadequate (missing key facts). 2 rounds is almost always sufficient. ## Rules - ALWAYS fan out — never search or fetch sequentially when you can parallelize. - If a page fails to fetch, skip it and proceed with what you have. - Be specific and concrete. Name exact versions, APIs, and tradeoffs. - Your final response MUST be written as plain text/markdown in your message — not inside a reasoning/thinking block. The text response is what gets returned to the caller. - Output ONLY the synthesised answer, no preamble. - Prefer official documentation, GitHub repos, and authoritative blogs over SEO-heavy aggregator sites. ` + parallelToolCallsPrompt(), }
SearchAgent performs deep parallel web research and synthesises findings.
Functions ¶
func BreakdownPrompt ¶
func BreakdownPrompt(messages []*session.MessageWithParts, archivePaths []string) string
BreakdownPrompt constructs the user message for the breakdown agent from the plan conversation. archivePaths contains filesystem paths to previously completed plan markdown files for this project. Only the paths are mentioned — the agent reads them via its file tools if needed.
func LoadAgentMD ¶
LoadAgentMD discovers and loads AGENT.md files by walking from dir up to the filesystem root. Files are returned in root-to-leaf order (outermost first), so that closer/leaf files appear later in the concatenated result and naturally take precedence for the LLM.
Missing files are silently skipped. Permission or read errors are logged as warnings and the file is skipped.
func LoadMemoryMD ¶ added in v0.4.0
LoadMemoryMD discovers and loads MEMORY.md files by walking from dir up to the filesystem root. Files are returned in root-to-leaf order (outermost first), so that closer/leaf files appear later in the concatenated result and naturally take precedence for the LLM.
Missing files are silently skipped. Permission or read errors are logged as warnings and the file is skipped.
func WithLoopControl ¶ added in v0.18.0
func WithLoopControl(ctx context.Context, lc *LoopControl) context.Context
WithLoopControl returns a context carrying the given LoopControl. RunLoop retrieves it via LoopControlFromContext. Call sites that do not need guidance (CLI one-shot, search sessions, indexer) simply don't wrap the context — LoopControlFromContext returns nil and the loop behaves exactly as before.
func WithoutLoopControl ¶ added in v0.19.1
WithoutLoopControl returns a copy of ctx with any LoopControl value cleared (set to nil). This is used by nested loop invocations — notably the deep_search tool's RunSearchSession — so the child loop does not inherit the parent session's LoopControl. Without this, the child loop would drain the parent's pending guidance (stealing mid-loop instructions) and overwrite the parent's stream/tool cancel funcs, hijacking the parent's guidance side-channel for the duration of the search.
Types ¶
type Agent ¶
Agent defines an agent configuration with available tools and system prompt.
type LoopControl ¶ added in v0.18.0
type LoopControl struct {
// contains filtered or unexported fields
}
LoopControl provides a side-channel for injecting mid-loop guidance into a running agent loop without starting a new user turn. It lets the user send a new instruction that the loop picks up at the top of the next iteration, and optionally cancel the currently-running tool call without killing the whole loop.
The guidance is ephemeral: it is never persisted to the database message history. Instead it is injected as a trailing system-prompt entry on the next LLM call. This avoids interactions with compaction boundaries, findLastTextUserMessageIndex turn-slicing, and agentic-memory <prior_context> filtering — all of which key off persisted user messages.
func LoopControlFromContext ¶ added in v0.18.0
func LoopControlFromContext(ctx context.Context) *LoopControl
LoopControlFromContext extracts the LoopControl from a context, or nil.
func NewLoopControl ¶ added in v0.18.0
func NewLoopControl() *LoopControl
NewLoopControl creates a fresh LoopControl.
func (*LoopControl) CancelAll ¶ added in v0.19.0
func (lc *LoopControl) CancelAll() bool
CancelAll cancels both the LLM stream and any running tool execution. This is the full "stop whatever you're doing right now" entry point used by the guidance handler so the user does not have to wait for the model to finish generating or for a long-running tool to complete before the loop picks up the new guidance. Returns true if at least one cancellation was issued.
func (*LoopControl) CancelStream ¶ added in v0.19.0
func (lc *LoopControl) CancelStream() bool
CancelStream cancels the currently-running LLM stream, if any. Returns true if a stream cancellation was issued, false if no stream is in progress (or the control is nil). This is the primary mechanism for making mid-loop guidance feel responsive: it interrupts the model's generation so the loop can immediately proceed to the next iteration where it drains the guidance.
func (*LoopControl) CancelTool ¶ added in v0.18.0
func (lc *LoopControl) CancelTool() bool
CancelTool cancels the currently-running tool execution batch, if any. Returns true if a tool cancellation was issued, false if no tools are currently running (or the control is nil).
func (*LoopControl) ClearStreamCancel ¶ added in v0.19.0
func (lc *LoopControl) ClearStreamCancel()
ClearStreamCancel removes the stored stream-cancel func without calling it. Called by RunLoop after the stream is fully consumed (or the guidance handler after it has called the cancel and the stream has wound down).
func (*LoopControl) ClearToolCancel ¶ added in v0.18.0
func (lc *LoopControl) ClearToolCancel()
ClearToolCancel removes the stored tool-cancel func without calling it. Called by RunLoop after tool execution completes normally.
func (*LoopControl) DrainGuidance ¶ added in v0.18.0
func (lc *LoopControl) DrainGuidance() string
DrainGuidance returns and clears all pending guidance texts. Called at the top of each loop iteration by RunLoop. Returns "" when nothing is pending.
func (*LoopControl) HasPendingGuidance ¶ added in v0.18.0
func (lc *LoopControl) HasPendingGuidance() bool
HasPendingGuidance reports whether there is undelivered guidance waiting.
func (*LoopControl) PushGuidance ¶ added in v0.18.0
func (lc *LoopControl) PushGuidance(text string)
PushGuidance appends a guidance text to the pending queue. Safe for concurrent use (called from the HTTP handler goroutine while the loop runs in its own goroutine).
func (*LoopControl) SetStreamCancel ¶ added in v0.19.0
func (lc *LoopControl) SetStreamCancel(cancel context.CancelFunc)
SetStreamCancel registers the cancel func for the currently-running LLM stream. Called by RunLoop just before calling StreamChat. The stored func is used by CancelStream to interrupt the stream without killing the loop. RunLoop clears it (and calls it to release the child context) after the stream is fully consumed.
func (*LoopControl) SetToolCancel ¶ added in v0.18.0
func (lc *LoopControl) SetToolCancel(cancel context.CancelFunc)
SetToolCancel registers the cancel func for the currently-running tool execution batch. Called by RunLoop before launching parallel tool calls. The stored func is used by CancelTool to interrupt only the tools, not the loop. RunLoop clears it (and calls it to release the context) after wg.Wait() returns.
type LoopRunner ¶
type LoopRunner struct {
Store *session.Store
Bus *bus.Bus
Registry *provider.Registry
DefaultProvider provider.Provider
Tools *tool.Registry
Dir string
MaxSteps int
Memory *memory.Memory
MCP *mcp.Client
NoteStore *note.Store
}
LoopRunner orchestrates the agent loop for a session.
func (*LoopRunner) RunLoop ¶
func (lr *LoopRunner) RunLoop(ctx context.Context, sessionID session.SessionID, agentName string, viewportWidth int, viewportHeight int) error
RunLoop executes the core agent loop: prompt -> stream -> tools -> loop back.
func (*LoopRunner) RunSearchSession ¶ added in v0.8.0
func (lr *LoopRunner) RunSearchSession(ctx context.Context, query, dir, model string) (string, error)
RunSearchSession creates an ephemeral search-agent session, runs the full loop, and returns the synthesised assistant text. The session is deleted on completion. This is called by tool.DeepSearchTool via the tool.DeepSearchFunc contract.
type TaskDefinition ¶
type TaskDefinition struct {
Title string `json:"title"`
Description string `json:"description"`
Dependencies []int `json:"dependencies"`
Effort string `json:"effort"`
Complexity string `json:"complexity"`
OrderIndex int `json:"orderIndex"`
}
TaskDefinition represents a single task parsed from the breakdown agent's JSON output.
func ParseTasks ¶
func ParseTasks(text string) ([]TaskDefinition, error)
ParseTasks extracts and parses the task definitions from the breakdown agent's response text. It handles cases where the LLM wraps the JSON in markdown code fences or adds preamble.