The project
Taskmind is a task platform with workspaces, projects, sprints, and lists. Its AI features assign tasks to team members and find schedule conflicts. We built it as a team of three for a university project. My teammates built the Angular app and most of the feature modules in the API. I built three parts: the API foundation, the agent service, and the deploys.
API foundation
I started the NestJS project and set up the parts that every module depends on:
- Prisma with PostgreSQL, and the first schema.
- JWT authentication with Passport, a user module with validation, and an admin guard for user management.
- Email verification and password reset. The templates load asynchronously, and the code escapes tokens and names before they go into links and HTML.
- A shared response format and global error filters, so every endpoint returns errors the same way.
- Bun as the runtime and script runner.
Agent service
The AI features live in a separate Python service. It is a FastMCP server with three tools, and each tool runs a PydanticAI agent on Gemini 2.5 Flash:
- Task assignment gives each task to one member. It weighs skill match, current workload, priority, and due date, and it returns a reason for each choice.
- Conflict detection finds scheduling, technical, and resource conflicts, such as clashing deadlines or an overloaded member, and labels each one with the tasks and people involved.
- Conflict resolution takes those conflicts and reassigns the affected tasks, with a reason for each change.
The NestJS API starts the agent service as a child process. The command is configurable, so the same build runs on a laptop and on the server.
The message labels describe each step. They are not the exact MCP payloads.
Assign
- The NestJS API starts the agent service as a child process. The command is configurable, so the same build runs on a laptop and on the server.
- The API calls an MCP tool. Task assignment gives each task to one member, based on skill match, workload, priority, and due date.
- The tool runs a PydanticAI agent on Gemini 2.5 Flash, with a Pydantic output type.
- The model must return data that matches that type. PydanticAI checks it before the tool returns.
- The API gets typed results over MCP, not free text that it must parse.
Detect
- The NestJS API starts the agent service as a child process. The command is configurable, so the same build runs on a laptop and on the server.
- The API calls an MCP tool. Conflict detection finds scheduling, technical, and resource conflicts.
- The tool runs a PydanticAI agent on Gemini 2.5 Flash, with a Pydantic output type.
- The model must return data that matches that type. PydanticAI checks it before the tool returns.
- The API gets typed results over MCP, not free text that it must parse.
Resolve
- The NestJS API starts the agent service as a child process. The command is configurable, so the same build runs on a laptop and on the server.
- The API calls an MCP tool. Conflict resolution reassigns the tasks behind each conflict.
- The tool runs a PydanticAI agent on Gemini 2.5 Flash, with a Pydantic output type.
- The model must return data that matches that type. PydanticAI checks it before the tool returns.
- The API gets typed results over MCP, not free text that it must parse.
Each agent has a Pydantic output type. The model must return data that matches the schema, so the API gets typed results, not free text that it must parse. The API starts the agent service as a child process and talks to it over MCP. I made the command configurable, so the same build works on a laptop and on the server.
Deploys
The API runs on Oracle Cloud under systemd, behind Caddy with TLS. I wrote the deploy scripts: build locally, upload with rsync, swap the release on the server, check health, and roll back on failure. These scripts later became the starting point for minideploy.