Skip to main content

Agentic Django

Agentic Django banner

Agentic Django is a reusable Django 6 app that wraps the OpenAI Agents SDK with Django-friendly primitives (sessions, runs, and background tasks). The example project lives in the sibling agentic-django-example repo.

Requirements

  • Python 3.12+
  • Django 6.x

Repository docs

Maintainers and coding agents should start with docs/index.md. The current architecture map lives in docs/architecture.md, validation guidance lives in docs/quality.md, and the embedded downstream-integration skill is documented in docs/skills.md.

Why use it

Building agentic workflows in Django usually means stitching together the OpenAI Agents SDK, persistence, and async execution on your own. This project gives you a consistent, Django-native way to:

  • kick off multi-step agent runs from views or services
  • persist conversation history and run status in your database
  • check progress later from any UI or API client
  • keep runs private to each authenticated user
  • reuse the same primitives across multiple apps or projects

Benefits

  • Django-first integration with models, admin, templates, and URL patterns
  • simple async model using Django 6 tasks (no Celery required)
  • stable polling UX for HTMX or REST clients
  • per-user ownership baked into queries and views
  • flexible registry so each project can provide its own agents

How it helps

If you have a workflow that can take minutes, branch into tools, or write to session memory, you can run it as a background task and poll for status just like any other Django async job. You do not need to keep a request open or build custom state tracking.

Usage examples

Create a run from a view and enqueue it for background execution:

from django.http import JsonResponse

from agentic_django.models import AgentRun, AgentSession
from agentic_django.services import enqueue_agent_run

def submit_run(request):
    session, _ = AgentSession.objects.get_or_create(
        owner=request.user,
        session_key=request.POST["session_key"],
    )
    run = AgentRun.objects.create(
        session=session,
        owner=request.user,
        agent_key="demo",
        input_payload=request.POST["input"],
    )
    enqueue_agent_run(str(run.id))
    return JsonResponse({"run_id": str(run.id), "status": run.status})

Check run status later from a UI or API client:

from django.http import JsonResponse
from django.shortcuts import get_object_or_404

from agentic_django.models import AgentRun

def run_status(request, run_id):
    run = get_object_or_404(AgentRun, id=run_id, owner=request.user)
    return JsonResponse({
        "status": run.status,
        "final_output": run.final_output,
    })

HTMX

If you are using the package's HTMX-oriented views and fragments, add django-htmx to your project so requests expose request.htmx and you can use the vendored script tags with Django 6 CSP nonces:

INSTALLED_APPS = [
    # ...
    "django_htmx",
    "agentic_django.apps.AgenticDjangoConfig",
]

MIDDLEWARE = [
    # ...
    "django_htmx.middleware.HtmxMiddleware",
]
{% load django_htmx static %}
<link rel="stylesheet" href="{% static 'agentic_django/agentic_django.css' %}">
{% htmx_script %}
{% django_htmx_script %}

If you are only using the JSON endpoints, you can omit django_htmx and its middleware.

HTMX polling + coordinated updates:

<div
  id="run-container-{{ run.id }}"
  data-status="{{ run.status }}"
  hx-get="{% url 'agents:run-fragment' run.id %}"
  hx-trigger="load delay:1s, every 2s"
  hx-target="#run-container-{{ run.id }}"
  hx-swap="outerHTML"
>
  {% load agentic_django_tags %}
  {% agent_run_fragment run %}
</div>

The fragment endpoint returns HttpResponseStopPolling when a run reaches a terminal state, so HTMX swaps in the final HTML and stops polling without extra client-side teardown code.

The package's fragment responses also emit HX-Trigger: run-update on each refresh so dependent panels can piggyback on the run poll loop instead of starting their own:

# Implemented in the package's fragment views.
from django.shortcuts import render
from django_htmx.http import trigger_client_event

response = render(request, "agentic_django/partials/run_fragment.html", {"run": run})
return trigger_client_event(response, "run-update")
<div id="conversation-panel"
     hx-get="{% url 'agents:session-items' session.session_key %}"
     hx-trigger="run-update from:body"
     hx-target="#conversation-contents"
     hx-swap="innerHTML">
  ...
</div>

Template override note: if you create templates/agentic_django/... in your project, Django will use those files instead of the package templates with the same path. This is useful for customization, but it can hide edits made in the package templates.

Styling (optional)

The package ships a minimal stylesheet for the default fragments. If you are not already including it via the HTMX setup above, add it to your base template:

{% load static %}
<link rel="stylesheet" href="{% static 'agentic_django/agentic_django.css' %}">

Configuration

Add the app and configure the agent registry in settings.py:

INSTALLED_APPS = [
    # ...
    "agentic_django.apps.AgenticDjangoConfig",
]

AGENTIC_DJANGO_AGENT_REGISTRY = "my_project.agent_registry.get_agent_registry"
AGENTIC_DJANGO_DEFAULT_AGENT_KEY = "default"
AGENTIC_DJANGO_DEFAULT_RUN_OPTIONS = {"max_turns": 6}
AGENTIC_DJANGO_CONCURRENCY_LIMIT = None  # auto: CPU count

# django-tasks backend selection (Immediate by default, RQ in production)
TASKS = {
    "default": {
        "BACKEND": "django_tasks.backends.immediate.ImmediateBackend",
    }
}

RQ_QUEUES = {
    "default": {
        "URL": "redis://localhost:6379/0",
    }
}

# Switch to RQ-backed tasks in production
TASKS["default"]["BACKEND"] = "django_tasks.backends.rq.RQBackend"

# Optional: enable event streaming persistence
AGENTIC_DJANGO_ENABLE_EVENTS = True

# Optional: basic abuse protection for run creation
AGENTIC_DJANGO_RATE_LIMIT = "20/m"
AGENTIC_DJANGO_MAX_INPUT_BYTES = 20_000
AGENTIC_DJANGO_MAX_INPUT_ITEMS = 20

# Optional: override startup recovery (default: requeue)
AGENTIC_DJANGO_STARTUP_RECOVERY = "fail"

# Optional: cleanup policy for old records
AGENTIC_DJANGO_CLEANUP_POLICY = {
    "events_days": 7,
    "runs_days": 30,
    "runs_statuses": ["completed", "failed"],
    "sessions_days": 90,
    "sessions_require_empty": True,
    "batch_size": 500,
}

Optional dependencies

  • RQ-backed tasks: pdm install -G rq
  • Postgres driver: pdm install -G postgres

Event streaming (optional)

When AGENTIC_DJANGO_ENABLE_EVENTS = True, each agent run persists semantic events (tool calls, tool outputs, message items). Poll for events with:

GET /runs/<uuid:run_id>/events/?after=<sequence>&limit=<n>

You can also subscribe to the Django signal agent_run_event to push UI updates after each event is stored.

Provide a registry that returns agent factories:

from agents import Agent
from my_project.models import MyModelProvider

def get_agent_registry():
    def build_default():
        return Agent(
            name="Support Agent",
            instructions="Help the user with account issues.",
            model=MyModelProvider(),
        )

    return {"default": build_default}

Operations

Prune old data with the cleanup command (uses AGENTIC_DJANGO_CLEANUP_POLICY by default):

python manage.py agentic_django_cleanup --dry-run
python manage.py agentic_django_cleanup --events-days 14 --runs-days 60

Recover runs stuck in running after a restart:

python manage.py agentic_django_recover_runs --mode=fail
python manage.py agentic_django_recover_runs --mode=requeue

Startup recovery runs on the first run dispatch/execution in each process, so it does not touch the database during app initialization.

Security notes

  • Enable Django 6’s Content Security Policy support where feasible, and open connect-src only to the endpoints your UI needs (for polling or tooling).
  • Keep agent tool registries scoped; do not expose powerful tools to untrusted user input without additional validation or allowlists.

Example project

The sample project lives in the sibling agentic-django-example repo. See its README for setup, Docker, and run instructions.

Tests

pdm run test

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentic_django-0.2.1.tar.gz (23.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentic_django-0.2.1-py3-none-any.whl (28.0 kB view details)

Uploaded Python 3

File details

Details for the file agentic_django-0.2.1.tar.gz.

File metadata

  • Download URL: agentic_django-0.2.1.tar.gz
  • Upload date:
  • Size: 23.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agentic_django-0.2.1.tar.gz
Algorithm Hash digest
SHA256 3f1d0812d75b712b1e35d3e8563f303d634d9e53335eab223f4042e3782eb01d
MD5 a104c537499a512508319948624ed93f
BLAKE2b-256 451bbf60cf745024a61ec5f3104a6ecc340d26583ec0a1b459fbda4ceef37ab8

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentic_django-0.2.1.tar.gz:

Publisher: python-publish.yml on btfranklin/agentic-django

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agentic_django-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: agentic_django-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 28.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agentic_django-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ea6df55e4e82ba7136d874dba7199da37d225b8df0c201f3f9498dc440d5790c
MD5 afd45a91beb4ee212795a0f55224eebb
BLAKE2b-256 4fc898afc61523175a32a571024820bd7574f1eb29a67a54510c3152f5b81ffe

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentic_django-0.2.1-py3-none-any.whl:

Publisher: python-publish.yml on btfranklin/agentic-django

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page