docs/current_docs/getting-started/quickstarts/agent/inproject.mdx
import PartialIde from '@partials/_ide.mdx'; import VideoPlayer from '@components/VideoPlayer';
Now that you've learned the basics of creating an AI agent with Dagger in Build an AI agent, its time to apply those lessons to a more realistic use case. In this guide, you will build an AI agent that builds features for an existing project.
For this guide you will start with a Daggerized project. The agent will use the Dagger functions in this project that are already used locally and in CI for testing the project.
This quickstart will take you approximately 10 minutes to complete. You should ideally have completed the AI agent and CI quickstarts and should be familiar with programming in Go, Python, TypeScript, PHP, or Java.
Before beginning, ensure that:
This quickstart uses the Daggerized project from the CI quickstart. To verify that your project is in the correct state, change to the project's working directory and list the available Dagger Functions:
cd hello-dagger
dagger functions
This should show:
Name Description
build Build the application container
build-env Build a ready-to-use development environment
publish Publish the application container after building and testing it on-the-fly
test Return the result of running unit tests
The goal of this quickstart is to create an agent to interact with the existing codebase and add features to it. This means that the agent needs the ability to list, read and write files in the project directory.
To give the agent these tools, create a Dagger submodule called workspace. This module will have Dagger Functions to list, read, and write files. The agent can use these Dagger Functions to interact with the codebase. By giving the agent a module with a limited set of tools, the agent has less room for error and will be more successful at its tasks.
```shell
dagger init --sdk=go .dagger/workspace
```
Replace the `.dagger/workspace/main.go` file with the following contents:
```go file=./snippets/part2/workspace/go/main.go
```
</TabItem>
<TabItem value="python" label="Python">
Start by creating the submodule:
```shell
dagger init --sdk=python .dagger/workspace
```
Replace the `.dagger/workspace/src/workspace/main.py` file with the following contents:
```python file=./snippets/part2/workspace/python/src/workspace/main.py
```
</TabItem>
<TabItem value="typescript" label="Typescript">
Start by creating the submodule:
```shell
dagger init --sdk=typescript .dagger/workspace
```
Replace the `.dagger/workspace/src/index.ts` file with the following contents:
```typescript file=./snippets/part2/workspace/typescript/src/index.ts
```
</TabItem>
<TabItem value="php" label="PHP">
Start by creating the submodule:
```shell
dagger init --sdk=php .dagger/workspace
```
Replace the `.dagger/workspace/src/Workspace.php` file with the following contents:
```php file=./snippets/part2/workspace/php/src/Workspace.php
```
</TabItem>
<TabItem value="java" label="Java">
Start by creating the submodule:
```shell
dagger init --sdk=java .dagger/workspace
```
Replace the `.dagger/workspace/src/main/java/io/dagger/modules/workspace/Workspace.java` file with the following contents:
```java file=./snippets/part2/workspace/java/src/main/java/io/dagger/modules/workspace/Workspace.java
</TabItem>
</Tabs>
In this Dagger module, each Dagger Function performs a different operation:
- The `read-file` Dagger Function reads a file in the workspace.
- The `write-file` Dagger Function writes a file to the workspace.
- The `list-files` Dagger Function lists all the files in the workspace.
- The `test` Dagger Function runs the tests on the files in the workspace.
See the functions of the new workspace module:
```shell
dagger -m .dagger/workspace functions
This should list the following functions:
Name Description
list-files List all of the files in the Workspace
read-file Read a file in the Workspace
source the workspace source code
test Return the result of running unit tests
write-file Write a file to the Workspace
Now install the new submodule as a dependency to the main module:
dagger install ./.dagger/workspace
This agent will make changes to the application and use the existing test function from the Daggerized CI pipeline to validate the changes.
```go file=./snippets/part2/agent/go/agent.go.snippet
```
</TabItem>
<TabItem value="python" label="Python">
Add the following new function to the main Dagger module in `.dagger/src/hello_dagger/main.py`:
```python file=./snippets/part2/agent/python/agent.py.snippet
```
</TabItem>
<TabItem value="typescript" label="Typescript">
Add the following new function to the main Dagger module in `.dagger/src/index.ts`:
```typescript file=./snippets/part2/agent/typescript/agent.ts.snippet
```
</TabItem>
<TabItem value="php" label="PHP">
Add the following new function to the main Dagger module in `.dagger/src/HelloDagger.php`:
```php file=./snippets/part2/agent/php/agent.php.snippet
```
</TabItem>
<TabItem value="java" label="Java">
Add the following new function to the main Dagger module in `.dagger/src/main/java/io/dagger/modules/hellodagger/HelloDagger.java`:
```java file=./snippets/part2/agent/java/agent.java.snippet
```
Be sure to add imports for the following:
```Java
import io.dagger.client.Client; import io.dagger.client.Env; import io.dagger.client.File; import io.dagger.client.LLM; import io.dagger.client.Workspace; ``` </TabItem> </Tabs>
This code creates a Dagger Function called develop that takes an assignment and codebase as input and returns a Directory with the modified codebase containing the completed assignment.
There are a few important points to note here:
environment is the environment to define inputs and outputs for the agent. Each input and output provides a description which acts as a declarative form of prompting.workspace sub-module installed and automatically generates bindings for it: with-workspace-input and with-workspace-output. These bindings can be used to provide (or retrieve) the workspace to the agent.The final step is to add the prompt file. Create a file at .dagger/develop_prompt.md with the following content:
You are a developer on the HelloDagger Vue.js project.
You will be given an assignment and the tools to complete the assignment.
Your assignment is: $assignment
## Constraints
- Before writing code, analyze the Workspace to understand the project.
- Do not make unnecessary changes.
- Always run tests to validate your code changes.
- Do not stop until you have completed the assignment and the tests pass.
:::note This prompt is more structured than the prompt from the first quickstart. The tasks the agent will be asked to complete will be more complex because its making modifications to an existing codebase and will need to understand more context. To create a reliable agent that can operate with more complexity, the prompt structure and tools are extremely important. :::
To see the new function, run:
dagger functions
Type dagger to launch Dagger Shell in interactive mode.
Check the help text for the new Dagger Function:
.help develop
This should show how to use the develop function.
Make sure your LLM has been properly configured:
llm | model
This should show the model you've configured to use with your provider.
Call the agent with an assignment:
develop "make the main page blue"
If all goes well, the agent will explore the project to find the correct place to make the changes, write the appropriate changes, and then validate them by calling the test function.
:::tip If the agent misbehaves, try providing more guidance in the prompt file based on what went wrong. :::
<VideoPlayer src="/img/current_docs/getting-started/quickstarts/agent/develop.webm" alt="Run the agent" />Since the agent returns a Directory, use Dagger Shell to do more with that Directory. For example:
# Save the directory containing the completed assignment to a variable
completed=$(develop "make the main page blue")
# Get a terminal in the build container with the directory
build-env --source $completed | terminal
# Run the app with the updated source code
build --source $completed | as-service | up --ports 8080:80
# Save the changes to your filesystem
$completed | export .
# Exit
exit
Now you have built an agent that can write code for your project!
The next step is to take this agent and deploy it so that it can run automatically. For this part of the guide, you will configure GitHub so that when you label a GitHub issue with "develop", the agent will automatically pick up the task and open a pull request with its solution.
The following steps require that you used the GitHub template and have your own hello-dagger repository.
The develop-issue function will use the github-issue Dagger module from the Daggerverse. This module provides functions to read GitHub issues and create pull requests.
Install the dependency:
dagger install github.com/kpenfound/dag/github-issue@b316e472d3de5bb0e54fe3991be68dc85e33ef38
```go file=./snippets/part3/agent/go/agent.go.snippet
```
</TabItem>
<TabItem value="python" label="Python">
Add the following new function to the main Dagger module in `.dagger/src/hello_dagger/main.py`:
```python file=./snippets/part3/agent/python/agent.py.snippet
```
</TabItem>
<TabItem value="typescript" label="Typescript">
Add the following new function to the main Dagger module in `.dagger/src/index.ts`:
```typescript file=./snippets/part3/agent/typescript/agent.ts.snippet
```
Be sure to add `Secret` to the imports.
</TabItem>
<TabItem value="php" label="PHP">
Add the following new function to the main Dagger module in `.dagger/src/HelloDagger.php`:
```php file=./snippets/part3/agent/php/agent.php.snippet
```
Be sure to add imports for the following:
```php
use Dagger\Secret;
```
</TabItem>
<TabItem value="java" label="Java">
Add the following new function to the main Dagger module in `.dagger/src/main/java/io/dagger/modules/hellodagger/HelloDagger.java`:
```java file=./snippets/part3/agent/java/agent.java.snippet
```
Be sure to add imports for the following:
```java
import io.dagger.client.Secret; import io.dagger.client.GithubIssue; ``` </TabItem> </Tabs>
The develop-issue function connects the dots in the automation flow. It will be called when a GitHub issue is ready to be developed. Using the github-issue dependency, this code will:
Directory returned by the agentTo see the new function, run:
dagger functions
To configure new repository secrets:
GEMINI_API_KEYIf you signed up for Dagger Cloud, you should also configure a DAGGER_CLOUD_TOKEN repository secret to see your GitHub Actions traces in Dagger Cloud.
To find your Dagger Cloud token, navigate to the organization settings page using the cogwheel icon in the top navigation bar. Under the Tokens sub-menu, click the eye icon to view the token. You can also use this URL pattern: https://v3.dagger.cloud/{Your Org Name}/settings?tab=Tokens
.github/workflows/develop.yml with the following content:This snippet shows an example with Google Gemini by specifying GEMINI_API_KEY. Change this to match the repository secrets you created earlier.
This GitHub Actions workflow will call the develop-issue function when the label "develop" is added to an issue. The GitHub token passed to the agent has permissions to read issues, write contents, and write pull requests.
git add .
git commit -m'deploy agent to github'
git push
Congratulations! You created an agentic function with a Daggerized project and successfully ran it, both locally and in automatically in GitHub.
We encourage you to join our awesome community on Discord to introduce yourself and ask questions. And starring our GitHub repository is always appreciated!