How to Create, Configure, and Assign Tasks to Agents in Multica: A Complete Guide
You create tasks in Multica using TaskService methods like EnqueueTaskForIssue, configure agents with runtime settings and max_concurrent_tasks limits, and assign work either by setting an agent as an issue assignee or mentioning them in comments, after which the daemon claims and executes tasks via the CLI.
Multica treats every unit of AI agent work as a task stored in the agent_task_queue table. Understanding how to create, configure, and assign tasks to agents in Multica is essential for orchestrating automated workflows reliably. This guide examines the TaskService implementation in server/internal/service/task.go and the agent schema in server/pkg/db/generated/agent.sql.go to show you exactly how the task lifecycle operates from enqueue to completion.
Creating Tasks in Multica
The TaskService in server/internal/service/task.go provides three primary entry points for creating tasks, depending on the trigger source.
Enqueue Tasks from Issue Assignments
When an issue’s assignee_id points to an agent, the backend calls EnqueueTaskForIssue (lines 33‑75 in server/internal/service/task.go). This method validates the assignee, loads the agent record via GetAgent, and inserts a row into agent_task_queue using CreateAgentTask.
func (s *TaskService) EnqueueTaskForIssue(
ctx context.Context,
issue db.Issue,
triggerCommentID ...pgtype.UUID,
) (db.AgentTaskQueue, error)
The function maps the issue’s priority to an integer via priorityToInt, sets the agent’s runtime_id on the task, and optionally links a triggering comment ID. If the agent is archived or lacks a runtime, the enqueue fails immediately.
Trigger Tasks via Agent Mentions
For explicit mentions (e.g., @code-reviewer), use EnqueueTaskForMention (lines 77‑108). This bypasses the issue assignee requirement and accepts an agentID directly, allowing any agent to be triggered regardless of the issue’s current assignee.
func (s *TaskService) EnqueueTaskForMention(
ctx context.Context,
issue db.Issue,
agentID pgtype.UUID,
triggerCommentID pgtype.UUID,
) (db.AgentTaskQueue, error)
This method follows the same validation and insertion logic as EnqueueTaskForIssue, ensuring consistency in task creation while supporting flexible invocation patterns.
Create Chat Session Tasks
For ad-hoc assistant interactions, EnqueueChatTask (lines 11‑38) creates a task linked to a chat_session_id with medium priority (value 2). This is useful for real-time help requests that do not originate from repository issues.
func (s *TaskService) EnqueueChatTask(
ctx context.Context,
chatSession db.ChatSession,
) (db.AgentTaskQueue, error)
The method loads the agent associated with the chat session and inserts the task using CreateChatTask, returning the queued record for WebSocket broadcast.
Configuring Agents for Task Execution
Agent Configuration Fields
Before an agent can claim work, it must be properly configured in the agent table (defined in server/pkg/db/generated/agent.sql.go). Key fields include:
runtime_id– Links the agent to a runtime record that defines the daemon’s host and port.max_concurrent_tasks– Hard limit on parallel task execution; enforced byClaimTaskinserver/internal/service/task.go.runtime_mode/runtime_config– JSON configuration passed to the daemon (e.g., Docker image, environment variables).status– Automatically updated byTaskService.ReconcileAgentStatustoidleorworkingbased on active task count.
Runtime Setup
The daemon binary (cmd/multica daemon) registers itself using environment variables MULTICA_DAEMON_PORT and MULTICA_RUNTIME_ID. Create the runtime and agent via CLI:
# Create a runtime endpoint
multica runtime create my-runtime --url http://localhost:8081
# Create an agent with concurrency limit of 4
multica agent create my-agent \
--runtime-id $(multica runtime list | jq -r '.[] | select(.name=="my-runtime") | .id') \
--max-concurrent-tasks 4 \
--description "Code-review bot"
The CLI invokes REST endpoints that persist these values to the database, making the agent eligible for task assignment immediately.
Assigning Tasks to Agents
Issue-Based Assignment
When you create or update an issue with an assignee_id referencing an agent, the server automatically calls EnqueueTaskForIssue. Use the CLI to assign work:
multica issue create "Add linting" \
--description "Run golint on the repo" \
--assignee-id $(multica agent list | jq -r '.[] | select(.name=="my-agent") | .id')
Mention-Based Assignment
If a comment contains @agent-name, the comment handler resolves the agent ID and invokes EnqueueTaskForMention. This allows a single comment to trigger a task without modifying the issue’s primary assignee, supporting multi-agent workflows on a single issue.
Daemon Task Claiming and Execution
The daemon polls GET /api/daemon/tasks (handled by server/internal/daemon/client.go) and claims work via TaskService.ClaimTask (lines 65‑100):
- Claim – The daemon requests the next eligible task for its
agent_id. - Concurrency Check – If the agent’s running task count meets or exceeds
max_concurrent_tasks,ClaimTaskreturnsnil(no capacity). - Dispatch – Upon successful claim, the server broadcasts a
task:dispatchevent (defined inserver/pkg/protocol/events.go) containing the task ID and payload. - Execution – The daemon runs the agent CLI with
--task-id=$TASK_ID, then calls back to/api/daemon/tasks/$TASK_ID/completeor/fail, triggeringTaskService.CompleteTask(lines 42‑84) orFailTask.
Practical Implementation Examples
Programmatic Task Enqueueing in Go
// Initialize queries and services
qs := db.New(dbConn)
taskSrv := service.NewTaskService(qs, hub, eventBus)
// Load the assigned issue
issue, err := qs.GetIssue(ctx, issueID)
if err != nil {
log.Fatal(err)
}
// Enqueue the task
task, err := taskSrv.EnqueueTaskForIssue(ctx, issue)
if err != nil {
log.Fatalf("failed to enqueue: %v", err)
}
fmt.Printf("Task %s queued for agent %s with runtime %s\n",
task.ID, task.AgentID, task.RuntimeID)
This mirrors the production flow in server/internal/service/task.go, where hub and eventBus handle WebSocket notifications to the frontend.
CLI-Based Task Management
# Poll for tasks (runs continuously in production)
multica daemon poll
# Manually claim a specific task (debugging)
multica daemon claim --agent-id $(multica agent get my-agent --format=json | jq -r .id)
# Report completion after agent CLI finishes
multica daemon complete \
--task-id $TASK_ID \
--output "$(cat result.json)" \
--session-id $SESSION_ID \
--work-dir $PWD
Summary
- Create tasks using
EnqueueTaskForIssue,EnqueueTaskForMention, orEnqueueChatTaskinserver/internal/service/task.godepending on the trigger source. - Configure agents with a valid
runtime_idand setmax_concurrent_tasksto control parallelism; the daemon uses these values to constrain workload. - Assign tasks automatically by setting an agent as an issue assignee, or dynamically via
@agentmentions in comments. - The daemon claims tasks respecting concurrency limits defined in
server/pkg/db/generated/agent.sql.go, executes the agent CLI, and reports status viaTaskService.CompleteTaskorFailTask. - The server broadcasts
task:dispatch,task:progress, andtask:completedevents (defined inserver/pkg/protocol/events.go) to keep the frontend synchronized.
Frequently Asked Questions
How does Multica prevent an agent from being overloaded with tasks?
Multica enforces the max_concurrent_tasks field defined in the agent table. When the daemon calls TaskService.ClaimTask (lines 65‑100 in server/internal/service/task.go), the service checks the current running task count for that agent. If the count equals or exceeds the configured limit, ClaimTask returns nil, forcing the daemon to skip that cycle and poll again later.
What is the difference between EnqueueTaskForIssue and EnqueueTaskForMention?
EnqueueTaskForIssue requires the issue’s assignee_id to reference an agent and is typically triggered when an issue is created or updated. EnqueueTaskForMention accepts an explicit agentID parameter, allowing any agent to be triggered via a comment mention without changing the issue’s primary assignee, enabling multi-agent collaboration on a single issue.
How do I check if an agent has available capacity before assigning work?
While you cannot query capacity directly via the public CLI, the TaskService automatically validates capacity during the claim phase. For programmatic checks, inspect the agent_task_queue table for rows matching the agent ID with status running or claimed, and compare the count against the agent’s max_concurrent_tasks value stored in the agent table.
What happens when a task fails during execution?
When the agent CLI exits with an error, the daemon calls the /api/daemon/tasks/$TASK_ID/fail endpoint, which invokes TaskService.FailTask. This updates the task status to failed, records the exit code and stderr output in the database, triggers a WebSocket task:failed event to the frontend, and allows TaskService.ReconcileAgentStatus to update the agent’s status if no other tasks are running.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →