diff --git a/spring-ai-modules/pom.xml b/spring-ai-modules/pom.xml
index 341aed83f4ed..acb011928872 100644
--- a/spring-ai-modules/pom.xml
+++ b/spring-ai-modules/pom.xml
@@ -35,5 +35,6 @@
spring-ai-vector-stores
spring-ai-mcp-annotations
spring-ai-subagent-orchestrator
+ spring-ai-todowrite-tool
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/pom.xml b/spring-ai-modules/spring-ai-todowrite-tool/pom.xml
new file mode 100644
index 000000000000..bf557caf805d
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/pom.xml
@@ -0,0 +1,83 @@
+
+
+ 4.0.0
+
+
+ com.baeldung
+ spring-ai-modules
+ 0.0.1
+ ../pom.xml
+
+
+ spring-ai-todowrite-tool
+ spring-ai-todowrite-tool
+ spring-ai-todowrite-tool
+
+
+ 21
+ 2.0.0-M5
+ 4.0.6
+ 6.0.3
+ 6.0.3
+ 2.0.17
+ 1.5.18
+ 3.5.5
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+ false
+
+
+
+
+
+
+
+ org.springframework.ai
+ spring-ai-bom
+ ${spring-ai.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.ai
+ spring-ai-starter-model-openai
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.platform
+ junit-platform-launcher
+ ${junit-platform.version}
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+
+
+
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/Application.java b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/Application.java
new file mode 100644
index 000000000000..5829c970c3e8
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/Application.java
@@ -0,0 +1,33 @@
+package com.baeldung.springai.todowritetool;
+
+import com.baeldung.springai.todowritetool.config.TodoAgentService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Profile;
+
+@SpringBootApplication
+public class Application {
+
+ private static final Logger logger = LoggerFactory.getLogger(Application.class);
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+ @Bean
+ @Profile("!test")
+ CommandLineRunner demo(TodoAgentService todoAgentService) {
+ return args -> {
+ String response = todoAgentService.ask(
+ """
+ Track these steps as a todo list: set up the project, write the tool, add tests
+ """
+ );
+ logger.info("{}", response);
+ };
+ }
+}
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoItem.java b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoItem.java
new file mode 100644
index 000000000000..f8ad87c14b27
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoItem.java
@@ -0,0 +1,6 @@
+package com.baeldung.springai.todowritetool;
+
+public record TodoItem(String id, String content, Status status, Priority priority) {
+ public enum Status { pending, in_progress, completed }
+ public enum Priority { low, medium, high }
+}
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoService.java b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoService.java
new file mode 100644
index 000000000000..66d291e3089c
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoService.java
@@ -0,0 +1,21 @@
+package com.baeldung.springai.todowritetool;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class TodoService {
+
+ private final AtomicReference> todos = new AtomicReference<>(List.of());
+
+ public List write(List updatedTodos) {
+ todos.set(updatedTodos);
+ return updatedTodos;
+ }
+
+ public List read() {
+ return todos.get();
+ }
+}
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoWriteTool.java b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoWriteTool.java
new file mode 100644
index 000000000000..a4ce241dabab
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/TodoWriteTool.java
@@ -0,0 +1,30 @@
+package com.baeldung.springai.todowritetool;
+
+import java.util.List;
+
+import org.springframework.ai.tool.annotation.Tool;
+import org.springframework.ai.tool.annotation.ToolParam;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TodoWriteTool {
+
+ private final TodoService todoService;
+
+ public TodoWriteTool(TodoService todoService) {
+ this.todoService = todoService;
+ }
+
+ @Tool(description = "Create or update the structured todo list for the "
+ + "current session, replacing any previous list")
+ public List todoWrite(
+ @ToolParam(description = "The full list of todo items, including "
+ + "unchanged ones") List todos) {
+ return todoService.write(todos);
+ }
+
+ @Tool(description = "Read the current todo list for the session")
+ public List todoRead() {
+ return todoService.read();
+ }
+}
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/config/TodoAgentService.java b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/config/TodoAgentService.java
new file mode 100644
index 000000000000..f84432fc48ab
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/main/java/com/baeldung/springai/todowritetool/config/TodoAgentService.java
@@ -0,0 +1,31 @@
+package com.baeldung.springai.todowritetool.config;
+
+import com.baeldung.springai.todowritetool.TodoWriteTool;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TodoAgentService {
+
+ private final ChatClient chatClient;
+
+ public TodoAgentService(ChatClient.Builder chatClientBuilder, TodoWriteTool todoWriteTool) {
+ this.chatClient = chatClientBuilder.clone()
+ .defaultSystem("""
+ You are a task-tracking assistant.
+ When the user asks you to track, plan, or list steps, you MUST call the todoWrite tool
+ with a complete todo list. Use string ids such as "1", "2", "3", statuses
+ pending/in_progress/completed, and priorities high/medium/low.
+ After the tool returns, briefly confirm what was recorded.
+ """)
+ .defaultTools(todoWriteTool)
+ .build();
+ }
+
+ public String ask(String userMessage) {
+ return chatClient.prompt()
+ .user(userMessage)
+ .call()
+ .content();
+ }
+}
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/main/resources/application.properties b/spring-ai-modules/spring-ai-todowrite-tool/src/main/resources/application.properties
new file mode 100644
index 000000000000..3dfacd68cc2f
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.application.name=spring-ai-todowrite-tool
+spring.ai.openai.api-key=${OPENAI_API_KEY}
+spring.ai.openai.chat.options.model=gpt-4.1-mini
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/ApplicationIntegrationTest.java b/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/ApplicationIntegrationTest.java
new file mode 100644
index 000000000000..9737edfc3a89
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/ApplicationIntegrationTest.java
@@ -0,0 +1,14 @@
+package com.baeldung.springai.todowritetool;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+@SpringBootTest
+@ActiveProfiles("test")
+class ApplicationIntegrationTest {
+
+ @Test
+ void contextLoads() {
+ }
+}
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/TodoAgentServiceIntegrationTest.java b/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/TodoAgentServiceIntegrationTest.java
new file mode 100644
index 000000000000..85eff525a5d5
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/TodoAgentServiceIntegrationTest.java
@@ -0,0 +1,32 @@
+package com.baeldung.springai.todowritetool;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.baeldung.springai.todowritetool.config.TodoAgentService;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+
+@SpringBootTest
+@ActiveProfiles("test")
+@TestPropertySource(locations = "classpath:application-test.properties")
+class TodoAgentServiceIntegrationTest {
+
+ @Autowired
+ private TodoAgentService todoAgentService;
+
+ @Autowired
+ private TodoService todoService;
+
+ @Test
+ void whenUserAsksToTrackSteps_thenTodoListIsPopulated() {
+ String response = todoAgentService.ask(
+ "Track these steps as a todo list: set up the project, "
+ + "write the tool, add tests");
+
+ assertThat(response).isNotBlank();
+ assertThat(todoService.read()).isNotEmpty();
+ }
+}
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/TodoWriteToolUnitTest.java b/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/TodoWriteToolUnitTest.java
new file mode 100644
index 000000000000..f9dadfd80fa2
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/test/java/com/baeldung/springai/todowritetool/TodoWriteToolUnitTest.java
@@ -0,0 +1,27 @@
+package com.baeldung.springai.todowritetool;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+class TodoWriteToolUnitTest {
+
+ @Test
+ void whenTodoWriteIsCalled_thenTodoReadReturnsSameList() {
+ TodoService todoService = new TodoService();
+ TodoWriteTool todoWriteTool = new TodoWriteTool(todoService);
+ List todos = List.of(
+ new TodoItem("1", "Set up project", TodoItem.Status.completed, TodoItem.Priority.high),
+ new TodoItem("2", "Write TodoWriteTool", TodoItem.Status.in_progress, TodoItem.Priority.high),
+ new TodoItem("3", "Add tests", TodoItem.Status.pending, TodoItem.Priority.medium));
+
+ List written = todoWriteTool.todoWrite(todos);
+
+ assertThat(written).hasSize(3);
+ assertThat(todoWriteTool.todoRead())
+ .extracting(TodoItem::status)
+ .containsExactly(TodoItem.Status.completed, TodoItem.Status.in_progress, TodoItem.Status.pending);
+ }
+}
diff --git a/spring-ai-modules/spring-ai-todowrite-tool/src/test/resources/application-test.properties b/spring-ai-modules/spring-ai-todowrite-tool/src/test/resources/application-test.properties
new file mode 100644
index 000000000000..b659627b64d1
--- /dev/null
+++ b/spring-ai-modules/spring-ai-todowrite-tool/src/test/resources/application-test.properties
@@ -0,0 +1 @@
+spring.ai.openai.api-key=dummy-key-for-tests