doug
A Dagger-native sandboxed coding agent.
Installation
dagger install github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c
Entrypoint
Return Type
Doug !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
source | Directory | - | No description provided |
Example
dagger -m github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c call \
func (m *MyModule) Example() *dagger.Doug {
return dag.
Doug()
}
@function
def example() -> dagger.Doug:
return (
dag.doug()
)
@func()
example(): Doug {
return dag
.doug()
}
Types
Doug 🔗
Doug coding agent module
dev() 🔗
A CLI friendly entrypoint for starting a coding agent developing in a workdir.
Return Type
LLM !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
source | Directory ! | - | No description provided |
module | Module | - | No description provided |
Example
echo 'Custom types are not supported in shell examples'
func (m *MyModule) Example(source *dagger.Directory) *dagger.LLM {
return dag.
Doug().
Dev(source)
}
@function
def example(source: dagger.Directory) -> dagger.LLM:
return (
dag.doug()
.dev(source)
)
@func()
example(source: Directory): LLM {
return dag
.doug()
.dev(source)
}
agent() 🔗
Returns a Doug coding agent
Return Type
LLM !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
base | LLM ! | - | No description provided |
Example
echo 'Custom types are not supported in shell examples'
func (m *MyModule) Example(base *dagger.LLM) *dagger.LLM {
return dag.
Doug().
Agent(base)
}
@function
def example(base: dagger.LLM) -> dagger.LLM:
return (
dag.doug()
.agent(base)
)
@func()
example(base: LLM): LLM {
return dag
.doug()
.agent(base)
}
readFile() 🔗
Reads a file from the project directory.
HOW TO USE THIS TOOL: - Reads the first 2000 lines by default - Each line is prefixed with a line number followed by an arrow (→). Everything that follows the arrow is the literal content of the line. - You can specify an offset and limit to read line regions of a large file - If the file contents are empty, you will receive a warning. - If multiple files are interesting, you can read them all at once using multiple tool calls.
Return Type
String !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
filePath | String ! | - | No description provided |
offset | Integer | - | No description provided |
limit | Integer | - | No description provided |
Example
dagger -m github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c call \
read-file --file-path string
func (m *MyModule) Example(ctx context.Context, filePath string) string {
return dag.
Doug().
ReadFile(ctx, filePath)
}
@function
async def example(file_path: str) -> str:
return await (
dag.doug()
.read_file(file_path)
)
@func()
async example(filePath: string): Promise<string> {
return dag
.doug()
.readFile(filePath)
}
editFile() 🔗
Edits files by replacing text, creating new files, or deleting content. For moving or renaming files, use the BasicShell tool with the ‘mv’ command instead. For larger file edits, use the Write tool to overwrite files.
Before using this tool, use the ReadFile tool to understand the file’s contents and context
To make a file edit, provide the following: 1. file_path: The relative path to the file to modify within the project directory 2. old_string: The text to replace (must be unique within the file, and must match the file contents exactly, including all whitespace and indentation) 3. new_string: The edited text to replace the old_string 4. replace_all: Replace all occurrences of old_string (default false)
Special cases: - To create a new file: provide file_path and new_string, leave old_string empty - To delete content: provide file_path and old_string, leave new_string empty
The tool will replace ONE occurrence of old_string with new_string in the specified file by default. Set replace_all to true to replace all occurrences.
CRITICAL REQUIREMENTS FOR USING THIS TOOL:
UNIQUENESS: When replace_all is false (default), the old_string MUST uniquely identify the specific instance you want to change. This means:
- Include AT LEAST 3-5 lines of context BEFORE the change point
- Include AT LEAST 3-5 lines of context AFTER the change point
- Include all whitespace, indentation, and surrounding code exactly as it appears in the file
SINGLE INSTANCE: When replace_all is false, this tool can only change ONE instance at a time. If you need to change multiple instances:
- Set replace_all to true to replace all occurrences at once
- Or make separate calls to this tool for each instance
- Each call must uniquely identify its specific instance using extensive context
VERIFICATION: Before using this tool:
- Check how many instances of the target text exist in the file
- If multiple instances exist and replace_all is false, gather enough context to uniquely identify each one
- Plan separate tool calls for each instance or use replace_all
WARNING: If you do not follow these requirements: - The tool will fail if old_string matches multiple locations and replace_all is false - The tool will fail if old_string doesn’t match exactly (including whitespace) - You may change the wrong instance if you don’t include enough context
When making edits:
Ensure the edit results in idiomatic, correct code
Do not leave the code in a broken state
Always use absolute file paths (starting with /)
Remember: when making multiple file edits in a row to the same file, you should prefer to send all edits in a single message with multiple calls to this tool, rather than multiple messages with a single call each.
Return Type
Changeset !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
filePath | String ! | - | No description provided |
oldString | String ! | - | No description provided |
newString | String ! | - | No description provided |
replaceAll | Boolean | - | No description provided |
Example
dagger -m github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c call \
edit-file --file-path string --old-string string --new-string string
func (m *MyModule) Example(filePath string, oldString string, newString string) *dagger.Changeset {
return dag.
Doug().
EditFile(filePath, oldString, newString)
}
@function
def example(file_path: str, old_string: str, new_string: str) -> dagger.Changeset:
return (
dag.doug()
.edit_file(file_path, old_string, new_string)
)
@func()
example(filePath: string, oldString: string, newString: string): Changeset {
return dag
.doug()
.editFile(filePath, oldString, newString)
}
write() 🔗
File writing tool that creates or updates files in the filesystem, allowing you to save or modify text content.
WHEN TO USE THIS TOOL: - Use when you need to create a new file - Helpful for updating existing files with modified content - Perfect for saving code, configurations, or text data
HOW TO USE: - Provide the path to the file you want to write - Include the content to be written to the file - The tool will create any necessary parent directories
FEATURES: - Can create new files or overwrite existing ones - Creates parent directories automatically if they don’t exist - Checks if the file has been modified since last read for safety - Avoids unnecessary writes when content hasn’t changed
LIMITATIONS: - You should read a file before writing to it to avoid conflicts - Cannot append to files (rewrites the entire file)
TIPS: - Use the View tool first to examine existing files before modifying them - Use the BasicShell tool to verify the correct location when creating new files - Combine with Glob and Grep tools to find and modify multiple files
Return Type
Changeset !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
path | String ! | - | No description provided |
contents | String ! | - | No description provided |
Example
dagger -m github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c call \
write --path string --contents string
func (m *MyModule) Example(path string, contents string) *dagger.Changeset {
return dag.
Doug().
Write(path, contents)
}
@function
def example(path: str, contents: str) -> dagger.Changeset:
return (
dag.doug()
.write(path, contents)
)
@func()
example(path: string, contents: string): Changeset {
return dag
.doug()
.write(path, contents)
}
glob() 🔗
Fast file pattern matching tool that finds files by name and pattern, returning matching paths sorted by modification time (newest first).
WHEN TO USE THIS TOOL: - Use when you need to find files by name patterns or extensions - Great for finding specific file types across a directory structure - Useful for discovering files that match certain naming conventions
HOW TO USE: - Provide a glob pattern to match against file paths - Optionally specify a starting directory (defaults to current working directory) - Results are sorted with most recently modified files first
GLOB PATTERN SYNTAX: - ‘*’ matches any sequence of non-separator characters - ‘**’ matches any sequence of characters, including separators - ‘?’ matches any single non-separator character - ‘[…]’ matches any character in the brackets - ‘[!…]’ matches any character not in the brackets
COMMON PATTERN EXAMPLES: - ‘.js’ - Find all JavaScript files in the current directory - ‘**/.js’ - Find all JavaScript files in any subdirectory - ‘src/*/.{ts,tsx}’ - Find all TypeScript files in the src directory - ‘*.{html,css,js}’ - Find all HTML, CSS, and JS files
LIMITATIONS: - Results are limited to 100 files (newest first) - Does not search file contents (use Grep tool for that) - Hidden files (starting with ‘.’) are skipped
TIPS: - Patterns should use forward slashes (/) for cross-platform compatibility - For the most useful results, combine with the Grep tool: first find files with Glob, then search their contents with Grep - When doing iterative exploration that may require multiple rounds of searching, consider using the Task tool instead - Always check if results are truncated and refine your search pattern if needed
Return Type
Void !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
pattern | String ! | - | No description provided |
Example
dagger -m github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c call \
glob --pattern string
func (m *MyModule) Example(ctx context.Context, pattern string) {
return dag.
Doug().
Glob(ctx, pattern)
}
@function
async def example(pattern: str) -> None:
return await (
dag.doug()
.glob(pattern)
)
@func()
async example(pattern: string): Promise<void> {
return dag
.doug()
.glob(pattern)
}
grep() 🔗
Fast content search tool that finds files containing specific text or patterns, returning matching file paths sorted by modification time (newest first).
WHEN TO USE THIS TOOL: - Use when you need to find files containing specific text or patterns - Great for searching code bases for function names, variable declarations, or error messages - Useful for finding all files that use a particular API or pattern
HOW TO USE: - Provide a regex pattern to search for within file contents - Set literal_text=true if you want to search for the exact text with special characters (recommended for non-regex users) - Optionally specify starting paths (defaults to current working directory) - Optionally provide a glob patterns to filter which files to search - Use the ReadLogs tool to narrow down a large search result, analogous to piping grep to grep, head, or tail
REGEX PATTERN SYNTAX (when literal_text=false): - Supports standard regular expression syntax - ‘function’ searches for the literal text “function” - ‘log..Error’ finds text starting with “log.” and ending with “Error” - ‘import\s+.\s+from’ finds import statements in JavaScript/TypeScript
COMMON INCLUDE PATTERN EXAMPLES: - ‘.js’ - Only search JavaScript files - ‘.{ts,tsx}’ - Only search TypeScript files - ‘*.go’ - Only search Go files
LIMITATIONS: - Performance depends on the number of files being searched - Very large binary files may be skipped - Hidden files (starting with ‘.’) are skipped
IGNORE FILE SUPPORT: - Respects .gitignore patterns to skip ignored files and directories - Both ignore files are automatically detected in the search root directory
CROSS-PLATFORM NOTES: - Uses ripgrep (rg) command internally - File paths are normalized automatically for cross-platform compatibility
TIPS: - For faster, more targeted searches, first use Glob to find relevant files, then use Grep - When doing iterative exploration that may require multiple rounds of searching, consider using the Task tool instead - Always check if results are truncated and refine your search pattern if needed, or use ReadLogs to filter the result - Use literal_text=true when searching for exact text containing special characters like dots, parentheses, etc.
Return Type
String !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
pattern | String ! | - | No description provided |
literalText | Boolean | - | No description provided |
paths | [String ! ] ! | - | No description provided |
glob | [String ! ] ! | - | No description provided |
multiline | Boolean | - | No description provided |
content | Boolean | - | No description provided |
insensitive | Boolean | - | No description provided |
limit | Integer | - | No description provided |
Example
dagger -m github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c call \
grep --pattern string --paths string1 --paths string2 --glob string1 --glob string2
func (m *MyModule) Example(ctx context.Context, pattern string, paths []string, glob []string) string {
return dag.
Doug().
Grep(ctx, pattern, paths, glob)
}
@function
async def example(pattern: str, paths: List[str], glob: List[str]) -> str:
return await (
dag.doug()
.grep(pattern, paths, glob)
)
@func()
async example(pattern: string, paths: string[], glob: string[]): Promise<string> {
return dag
.doug()
.grep(pattern, paths, glob)
}
task() 🔗
Launch a new agent that has access to the same tools and environment.
When you are searching for a keyword or file and are not confident that you will find the right match on the first try, use the Task tool to perform the search for ou.
EXAMPLES: - If you are searching for a keyword like “config” or “logger”, or for questions like “which file does X?”, the Task tool is strongly recommended - If you want to read a specific file path, use the View or GlobTool tool instead of the Task tool, to find the match more quickly - If you are searching for a specific class definition like “class Foo”, use the GlobTool tool instead, to find the match more quickly
USAGE NOTES: - Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses - When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, u should send a text message back to the user with a concise summary of the result. - Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of s final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what formation the agent should return back to you in its final and only message to you. - The agent’s outputs should generally be trusted - IMPORTANT: The agent runs in a copy-on-write sandboxed environment. Any writes made by the agent will not be visible to the user, but will be available to the agent’s next invocation.
Return Type
String !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
description | String ! | - | No description provided |
prompt | String ! | - | No description provided |
Example
dagger -m github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c call \
task --description string --prompt string
func (m *MyModule) Example(ctx context.Context, description string, prompt string) string {
return dag.
Doug().
Task(ctx, description, prompt)
}
@function
async def example(description: str, prompt: str) -> str:
return await (
dag.doug()
.task(description, prompt)
)
@func()
async example(description: string, prompt: string): Promise<string> {
return dag
.doug()
.task(description, prompt)
}
todoWrite() 🔗
Keep track of your TODO list
WHEN TO USE THIS TOOL: - When a task requires 3 or more distinct steps or actions - To break down a complex task into smaller, manageable parts - When the user directly gave a sequence of tasks to perform (numbered or comma-separated) - When the user gave you more tasks in the middle of a conversation - When you want to see the full TODO list
SKIP THIS TOOL WHEN: - The task is trivial - The task is purely conversational or informational
HOW TO USE: - Call this function with the TODOs to record in each state (pending, in progress, completed) - TODOs are additive; you can call it with incremental updates for individual TODOs - The full TODO list will be printed in response - Every pending TODO must be eventually completed before your task is completed - To print the current TODO list, call this function with no arguments
Return Type
Env !
Arguments
Name | Type | Default Value | Description |
---|---|---|---|
pending | [String ! ] ! | - | No description provided |
inProgress | [String ! ] ! | - | No description provided |
completed | [String ! ] ! | - | No description provided |
Example
dagger -m github.com/vito/daggerverse/doug@1011ac6b83046b55a45283aba10e25cf9e99e06c call \
todo-write --pending string1 --pending string2 --in-progress string1 --in-progress string2 --completed string1 --completed string2
func (m *MyModule) Example(pending []string, inProgress []string, completed []string) *dagger.Env {
return dag.
Doug().
TodoWrite(pending, inProgress, completed)
}
@function
def example(pending: List[str], in_progress: List[str], completed: List[str]) -> dagger.Env:
return (
dag.doug()
.todo_write(pending, in_progress, completed)
)
@func()
example(pending: string[], inProgress: string[], completed: string[]): Env {
return dag
.doug()
.todoWrite(pending, inProgress, completed)
}