> ## Documentation Index
> Fetch the complete documentation index at: https://docs-omnicoreagent.omnirexfloralabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Background Agents

> Run tracked OmniCoreAgent tasks outside the foreground request path

# Background Agents

Background agents run tracked OmniCoreAgent tasks outside the foreground request
path. Use the default in-memory store for local development, or choose `sql`,
`redis`, or `mongodb` when tasks, runs, attempts, leases, retries, and
cancellation state must survive process restarts. A task can run manually, once
at a fixed time, on an interval, or from a five-field cron expression. Each run
is tracked through queued, claimed, running, retrying, and terminal states.

Background execution is part of the core package:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
pip install omnicoreagent
```

Redis and MongoDB task stores use optional backend drivers:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
pip install "omnicoreagent[redis]"
pip install "omnicoreagent[mongodb]"
```

No storage configuration is required to start. `BackgroundAgentManager()` uses an
in-memory task store by default so the first run has no database requirement.
Use `task_store="sql"`, `task_store="redis"`, or `task_store="mongodb"` when
tasks, runs, attempts, leases, retries, and cancellation state must survive
process restarts.

The task store is separate from agent memory. `MemoryRouter` stores
conversation/session history. The task store stores operational background
state and owns the atomic claim, lease, retry, and schedule-cursor guarantees.

## Quick Start

Set `LLM_API_KEY` first, then run the example; no task-store configuration is
required.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import asyncio

from omnicoreagent import BackgroundAgentManager, OmniCoreAgent


async def main():
    agent = OmniCoreAgent(
        name="system_monitor",
        system_instruction="Check system health and write concise reports.",
        model_config={"provider": "openai", "model": "gpt-5.4-mini"},
    )

    manager = BackgroundAgentManager()
    await manager.register_agent("system_monitor", agent)
    await manager.register_task(
        task_id="health_report",
        agent_id="system_monitor",
        query="Check system health and summarize anything that needs attention.",
        schedule={"type": "manual"},
        timeout_seconds=60,
        retry_policy={"max_retries": 1, "initial_delay_seconds": 0},
    )

    run = await manager.run_now("health_report", wait=True)
    print(run.status)
    print(run.result_preview)


asyncio.run(main())
```

## Scheduled Runs

Start the manager when you want it to dispatch due schedules:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
await manager.register_task(
    task_id="hourly_report",
    agent_id="system_monitor",
    query="Write the hourly operational report.",
    schedule={"type": "interval", "seconds": 3600},
    overlap_policy="queue_next",
)

await manager.start()
```

The worker loop reads due schedules from the task store, creates a run exactly
once for each occurrence, advances the schedule state, claims queued runs, and
executes them with lease fencing.

## Runtime Controls

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
run = await manager.run_now("health_report")
latest = await manager.get_run(run.run_id)
attempts = await manager.list_attempts(run.run_id)
events = await manager.get_run_events(run.run_id)

await manager.cancel_run(run.run_id)
await manager.pause_task("hourly_report")
await manager.resume_task("hourly_report")
await manager.delete_task("hourly_report", delete_runs=True)
```

## Run Event Replay

Each run emits ordered lifecycle events with a run-local `sequence` number.
`get_run_events(run_id)` returns the most complete trace it can read from:

* the current process cache
* the run workspace `events.jsonl` mirror, when workspace event mirroring is enabled

If more than one source is available, OmniCoreAgent returns a complete terminal
trace first. If no source has reached a terminal event yet, it prefers the
process cache, then the workspace mirror. Sources with malformed or duplicate
run-local sequence numbers are ignored during replay selection. A valid source
uses contiguous integer sequence numbers starting at `1`.

Run-scoped lifecycle events include schedule dispatch, queueing, claiming,
start, heartbeat, retry, terminal status, and recovery transitions when those
transitions occur.

Durable restart replay needs workspace event mirroring enabled. If a process
exits with only in-memory events and no workspace mirror, the task store still
preserves run status, attempts, leases, and results, but old event history may
not be replayable.

## OmniServe API

When an agent is served through OmniServe, the server registers that agent with
the background manager during startup and exposes task control over HTTP:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST http://localhost:8000/background/tasks \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "health_report",
    "query": "Check system health and write the report.",
    "schedule": {"type": "manual"},
    "timeout_seconds": 60
  }'

curl -X POST http://localhost:8000/background/tasks/health_report/run \
  -H "Content-Type: application/json" \
  -d '{"wait": false}'
```

Use `{"wait": true}` when the HTTP request should wait for terminal run state.
If the OmniServe worker is running, the API waits for that worker-owned run. If
the worker is disabled, the API queues the run through the background manager
and drives that run inline through the same execution contract. If the run does
not finish before the background wait budget, OmniServe returns `504` and the
run remains inspectable through the background run endpoints. The wait budget is
derived from the configured request timeout and leaves a small margin for
OmniServe to return the structured response before the outer HTTP timeout. The
`504` response includes the `run_id`, `task_id`, latest `status`,
`wait_timeout_seconds`, and `request_timeout_seconds` in `detail`.

The background API includes manager status, task creation, task status, task
listing, pause, resume, delete, manual run, cancellation, run status, attempt
history, event replay, and workspace inspection.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl http://localhost:8000/background/status
curl http://localhost:8000/background/tasks/health_report/status
curl http://localhost:8000/background/runs/$RUN_ID
curl http://localhost:8000/background/runs/$RUN_ID/events
curl http://localhost:8000/background/runs/$RUN_ID/workspace
```

## Task Configuration

| Field              | Purpose                                                                  |
| ------------------ | ------------------------------------------------------------------------ |
| `task_id`          | Stable task identifier.                                                  |
| `agent_id`         | Registered agent that executes the task.                                 |
| `query`            | Instruction passed to the agent for each run.                            |
| `schedule`         | `manual`, `interval`, `cron`, or `once`.                                 |
| `timeout_seconds`  | Optional per-run timeout.                                                |
| `retry_policy`     | Retry count, delay, backoff, and retryable error types.                  |
| `overlap_policy`   | `skip_if_running`, `queue_next`, `cancel_previous`, or `allow_parallel`. |
| `session_policy`   | `task`, `run`, or `fixed` memory-session behavior.                       |
| `workspace_policy` | Workspace namespace used for run output.                                 |

## Persistent State

The task store is the source of truth for:

* registered agent specs
* task definitions
* schedule state and occurrence IDs
* runs and attempts
* leases, heartbeats, and cancellation flags

The current runtime includes the tracked run model, in-memory, SQL, Redis, and
MongoDB task stores, schedule dispatch, manual runs, retries with delay/backoff,
lease fencing, expired-lease recovery, cancellation, workspace lifecycle files,
and run event replay. Task, schedule, run, attempt, lease, retry, and
cancellation state is restart-persistent when the task store is SQL, Redis, or
MongoDB. Event history follows the replay rules above through the manager
process cache and workspace `events.jsonl` mirror.

Durable stores are tested at the manager boundary. A queued run can be created,
the manager can shut down, and a new manager over the same SQL, Redis, or
MongoDB task store can claim and complete that run. The in-memory store is only
for local development, tests, and single-process experiments.

Choose one durable backend per deployment. Use SQL/SQLite for local durability
or simple single-node services. Use Redis when your deployment already operates
Redis with persistence and no eviction for task-store keys. Use MongoDB when
MongoDB is your durable operational store.

Redis durable deployments need persistence enabled and a no-eviction policy for
task-store keys. MongoDB task-store writes use majority write concern.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
BackgroundAgentManager(task_store="sql")
BackgroundAgentManager(task_store={"backend": "redis", "url": "redis://localhost:6379/0"})
BackgroundAgentManager(
    task_store={
        "backend": "mongodb",
        "uri": "mongodb://localhost:27017",
        "database": "omnicoreagent",
    }
)
```
