# How the Local Daemon Runtime Executes Agent Tasks in Multica

> Discover how the Multica local daemon runtime efficiently executes agent tasks. Learn about its polling, claiming, and execution process for provider-specific binaries with real-time results.

- Repository: [multica-ai/multica](https://github.com/multica-ai/multica)
- Tags: internals
- Published: 2026-04-11

---

**The Multica local daemon is a lightweight Go process that continuously polls the Multica server, claims pending tasks via HTTP API, and executes provider-specific agent binaries (Claude, Codex, etc.) inside isolated work directories while streaming real-time results back to the server.**

The local daemon runtime in the multica-ai/multica repository serves as the execution bridge between Multica’s centralized task queue and local AI agent capabilities. Written in Go, it manages the complete lifecycle of agent tasks—from authentication and workspace registration through execution environment preparation to final result reporting—ensuring secure, isolated, and trackable agent operations on local infrastructure.

## Daemon Initialization and Registration

Upon startup, the daemon loads configuration via `daemon.LoadConfigFromFlags()`, authenticates with the Multica server, and registers its runtimes for each watched workspace. According to the source code in [`/server/internal/daemon/daemon.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/daemon.go) (lines 57-95), this initialization phase starts several background loops including heartbeat monitoring, configuration watching, and workspace synchronization.

```go
cfg, _ := daemon.LoadConfigFromFlags()
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
d := daemon.New(cfg, logger)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if err := d.Run(ctx); err != nil {
    logger.Error("daemon exited", "error", err)
}

```

## The Polling Loop: Claiming Tasks from the Server

The core orchestration logic resides in the `pollLoop` function, which runs indefinitely and is throttled by the `PollInterval` configuration. For every registered runtime ID, the daemon attempts to claim available tasks via `client.ClaimTask`. As implemented in [`/server/internal/daemon/daemon.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/daemon.go) (lines 84-108 and 119-130), successfully claimed tasks trigger the launch of a dedicated goroutine for isolated handling.

```go
for {
    runtimeIDs := d.allRuntimeIDs()
    for _, rid := range runtimeIDs {
        task, err := d.client.ClaimTask(ctx, rid)
        if err != nil { continue }
        if task != nil {
            go d.handleTask(ctx, *task) // each task runs in its own goroutine
        }
    }
    sleepWithContext(ctx, d.cfg.PollInterval)
}

```

## Task Execution Pipeline

### Environment Preparation

When `handleTask` initiates execution, it first locks the runtime map and notifies the server that the task has started. The `runTask` function then constructs a per-task execution environment using `execenv.Prepare` or reuses an existing directory via `execenv.Reuse` if available (as seen in [`/server/internal/daemon/daemon.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/daemon.go), lines 93-104). Runtime-specific metadata—including repository lists, skills, and agent instructions—is injected via `execenv.InjectRuntimeConfig` (lines 23-27).

```go
env, err := execenv.Prepare(execenv.PrepareParams{
    WorkspacesRoot: d.cfg.WorkspacesRoot,
    WorkspaceID:    task.WorkspaceID,
    TaskID:         task.ID,
    AgentName:      agentName,
    Provider:       provider,
    Task:           taskCtx,
}, d.logger)

```

### Agent Backend Construction

The daemon constructs an `agent.Backend` by locating the provider's executable path from `cfg.Agents[provider]` and building an environment variable map containing authentication tokens and daemon ports. This logic in [`/server/internal/daemon/daemon.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/daemon.go) (lines 56-62 and 34-41) supports multiple AI providers including Claude and Codex.

### Prompt Generation and Execution

A task-specific prompt is assembled using `BuildPrompt` (defined in [`/server/internal/daemon/prompt.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/prompt.go)) from task data including issue context, repository state, and skills. This prompt is passed to `backend.Execute` with parameters including the work directory, model name, timeout duration, and optional previous session ID (lines 31-38 and 79-84).

```go
backend, _ := agent.New(provider, agent.Config{
    ExecutablePath: entry.Path,
    Env:            agentEnv,
    Logger:         d.logger,
})

session, _ := backend.Execute(ctx, prompt, agent.ExecOptions{
    Cwd:      env.WorkDir,
    Model:    entry.Model,
    Timeout:  d.cfg.AgentTimeout,
})

```

## Real-Time Message Streaming

While the agent binary executes, the daemon consumes messages from the `session.Messages` channel in a separate goroutine. As documented in [`/server/internal/daemon/daemon.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/daemon.go) (lines 50-115), the implementation handles text output, thinking logs, tool-use requests, tool results, and error messages. These are batched and periodically flushed to the server via `client.ReportTaskMessages`. The daemon also maintains a `toolCount` for usage tracking.

```go
// Drain messages and forward to the server.
go func() {
    for msg := range session.Messages {
        // … batch & report via d.client.ReportTaskMessages …
    }
}()

result := <-session.Result

```

## Result Handling and Reporting

When the agent terminates, it sends a `TaskResult` on the `session.Result` channel. The daemon translates this result, extracts usage metrics, and records the work directory path for future reuse (lines 20-30 and 44-55). Depending on the final status, the daemon calls one of three server endpoints:

- **`client.CompleteTask`** for successful completions
- **`client.FailTask`** for execution errors  
- **`client.FailTask`** with a "blocked" comment for blocked tasks (lines 59-71)

### Cancellation and Cleanup

The daemon monitors task cancellation status every 5 seconds via a cancellable context. If the server marks a task as "cancelled" during execution (as shown in lines 104-112 and 122-131), the polling goroutine immediately cancels the agent context and discards partial results, ensuring clean termination.

## Summary

- The Multica local daemon runtime continuously polls the server via `client.ClaimTask` to discover pending work.
- Each task executes in an isolated environment prepared by `execenv.Prepare` or reused via `execenv.Reuse`.
- The daemon constructs provider-specific `agent.Backend` instances to launch Claude, Codex, or other supported binaries.
- Real-time output streams through `session.Messages` to the server via `client.ReportTaskMessages`.
- Task lifecycle management includes proper cancellation handling, result translation, and work directory persistence.

## Frequently Asked Questions

### How does the Multica daemon handle multiple concurrent tasks?

Each claimed task runs in its own goroutine spawned by `handleTask`, allowing the daemon to execute multiple agent sessions concurrently. The runtime map is locked during task initialization to prevent race conditions, while individual task contexts manage their own cancellation and resource isolation.

### What happens if an agent task is cancelled mid-execution?

The daemon creates a cancellable context for each task that polls the server every 5 seconds for cancellation status. If detected, the context is cancelled immediately, terminating the agent binary and discarding results without reporting completion to the server.

### Which files contain the core daemon orchestration logic?

The primary implementation resides in [`/server/internal/daemon/daemon.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/daemon.go), which contains the polling loop, task dispatch, and lifecycle management. Supporting logic includes [`/server/internal/daemon/execenv/execenv.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/execenv/execenv.go) for environment setup, [`/server/internal/daemon/client.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/client.go) for server communication, and [`/server/internal/daemon/prompt.go`](https://github.com/multica-ai/multica/blob/main//server/internal/daemon/prompt.go) for prompt construction.

### How does the daemon manage execution environments for different providers?

The daemon uses the `execenv` package to create isolated work directories per task, injecting runtime-specific configuration including repository contexts and skills via `execenv.InjectRuntimeConfig`. Work directories are preserved after task completion (`execenv.Reuse`) to maintain state across related operations.