Take your agent to production

Deploy your personal agent to Render with persistent storage and keep using it in Slack.

Deploy the agent from Talk to your agent in Slack to Render. You'll give it a stable HTTPS endpoint, store its tasks and notes in Postgres, and keep using the same Slack app.

You'll need a GitHub account and a Render account. This walkthrough provisions a paid Starter web service and Basic Postgres database. Check Render's pricing before deploying. Connecting a live instance to the hosted Control Plane also requires a plan that supports live connections.

Prepare your agent

The agent's behavior stays the same. Update personal_agent.py to select Postgres when DATABASE_URL is set and to support production authorization:

personal_agent.py
from os import environ, getenv

from agno.agent import Agent
from agno.db.postgres import PostgresDb, create_postgres_engine
from agno.db.sqlite import SqliteDb
from agno.fs import FileSystem
from agno.os import AgentOS
from agno.os.config import AuthorizationConfig
from agno.os.interfaces.slack import Slack

if getenv("RENDER") == "true" and not (
    getenv("OS_SECURITY_KEY") or getenv("JWT_VERIFICATION_KEY")
):
    raise RuntimeError("Configure AgentOS authentication before starting on Render.")

if database_url := getenv("DATABASE_URL"):
    db = PostgresDb(
        db_engine=create_postgres_engine(database_url),
    )
else:
    db = SqliteDb(db_file="personal_agent.db")

fs = FileSystem(db, namespace="personal-agent/{user_id}")

agent_instructions = """Help the user keep track of their tasks and useful notes.

Keep tasks and useful notes in your filesystem. Start with a simple structure,
group related information together, and split files by project or topic when
that makes them easier to maintain. Follow any organization the user requests.
Track task completion and due dates when provided.

Read the relevant files before answering or making changes. Create new files
as needed. Preserve unrelated entries when updating existing files.

Only say something is saved or updated after the file tool succeeds.
Keep replies brief and confirm what changed.
"""

agent = Agent(
    name="Personal Agent",
    model="openai:gpt-5.6",
    db=db,
    tools=[fs.tools()],
    instructions=[agent_instructions, fs.instructions()],
    add_history_to_context=True,
    add_datetime_to_context=True,
)

agent_os = AgentOS(
    agents=[agent],
    db=db,
    interfaces=[
        Slack(
            agent=agent,
            token=environ["SLACK_TOKEN"],
            signing_secret=environ["SLACK_SIGNING_SECRET"],
        )
    ],
    authorization=bool(getenv("JWT_VERIFICATION_KEY")),
    authorization_config=AuthorizationConfig(user_isolation=True),
    tracing=True,
)
app = agent_os.get_app()

if __name__ == "__main__":
    agent_os.serve(app="personal_agent:app", reload=True)

Render will use a separate start command without hot reload. After adding the dependencies below, you can still run uv run personal_agent.py locally with the environment variables from the previous page.

The initial deployment uses a generated OS security key. Once the service has a URL, you'll connect the Control Plane and configure JWT authorization with per-user data isolation.

Add your deployment files

Add the production dependencies

Add Postgres support and the cryptography package used to verify JWT signatures:

uv add "agno[os,sqlite,slack,postgres]==3.0.8" cryptography

This updates pyproject.toml and uv.lock. Commit both files so Render installs the same locked dependencies.

Keep local data and credentials out of Git

Create .gitignore:

.gitignore
.venv/
__pycache__/
.env
.env.*
*.db
*.db-*

Define the Render services

Create render.yaml in the project root:

render.yaml
services:
  - type: web
    name: personal-agent
    runtime: python
    plan: starter
    region: oregon
    numInstances: 1
    buildCommand: uv sync --locked --no-dev
    startCommand: uv run --no-sync uvicorn personal_agent:app --host 0.0.0.0 --port $PORT
    healthCheckPath: /health
    envVars:
      - key: PYTHON_VERSION
        value: 3.12.8
      - key: UV_VERSION
        value: 0.12.5
      - key: OPENAI_API_KEY
        sync: false
      - key: SLACK_TOKEN
        sync: false
      - key: SLACK_SIGNING_SECRET
        sync: false
      - key: OS_SECURITY_KEY
        generateValue: true
      - key: DATABASE_URL
        fromDatabase:
          name: personal-agent-db
          property: connectionString

databases:
  - name: personal-agent-db
    plan: basic-256mb
    region: oregon
    postgresMajorVersion: "17"
    databaseName: agent
    user: agent

The Blueprint creates the app and database in the same region and connects them using Render's internal database URL. You can change both region values before deploying.

Render provides uv when it finds uv.lock in the project root. The build installs from that lockfile and fails if it is out of date with pyproject.toml. The start command uses the environment prepared during the build.

The web service's regular filesystem is ephemeral. Postgres stores the agent's files, sessions, and traces separately, so they survive app restarts and redeployments.

The production database starts empty. Your local tasks and conversations remain in personal_agent.db; deploying the code does not copy them. Add your active tasks to the hosted agent after switching Slack to Render.

Deploy to Render

  1. Create an empty GitHub repository for this project. From your project directory, initialize Git and push the deployment files. Replace the remote URL below with your repository's URL:

    git init
    git add personal_agent.py pyproject.toml uv.lock render.yaml .gitignore
    git commit -m "Deploy personal agent"
    git branch -M main
    git remote add origin https://github.com/YOUR_USERNAME/personal-agent.git
    git push -u origin main
  2. In the Render dashboard, select NewBlueprint and connect your repository.

  3. Review the web service and database plans. Supply OPENAI_API_KEY, SLACK_TOKEN, and SLACK_SIGNING_SECRET when prompted. Use the credentials for the Slack app you already created.

  4. Deploy the Blueprint. Wait for the web service to become healthy, then copy its https://...onrender.com URL.

  5. Open that URL with /health appended to confirm the service is responding. Use the service's Logs tab if startup fails.

Connect and authorize the Control Plane

Connect with the generated security key

In Render, open the web service's Environment settings and copy its generated OS_SECURITY_KEY.

Open os.agno.com, select Connect OSLive, and enter your Render URL. Name it Personal Agent Production and configure security key authentication with that value.

Enable JWT authorization

In the Control Plane connection's SettingsOS & Security, enable Token-Based Authorization (JWT) and copy the generated public verification key.

In Render, add JWT_VERIFICATION_KEY to the web service's environment variables. Paste the complete public key, including the BEGIN PUBLIC KEY and END PUBLIC KEY lines. Save and deploy the change.

Once that deployment is healthy, use JWT authorization for the Control Plane connection and disable its security key authentication. JWT configuration takes precedence on the server.

Remove the bootstrap key

Confirm you can open the agent in the Control Plane with JWT authorization. Remove the OS_SECURITY_KEY entry from render.yaml, commit and push the change, and sync the Blueprint. Then remove the existing OS_SECURITY_KEY variable from the Render service's Environment settings if it remains.

Keep JWT_VERIFICATION_KEY configured. The app now starts with JWT authorization and user isolation enabled; Slack continues to verify incoming requests with its signing secret.

See authorization when you need to configure access for additional Control Plane users. File namespaces separate each Slack user's notes, while workspace app installation determines who can message the bot.

Switch Slack to your hosted agent

Open your app at Your Apps and update both endpoints:

SettingNew URL
Event SubscriptionsRequest URLhttps://YOUR-SERVICE.onrender.com/slack/events
Interactivity & ShortcutsRequest URLhttps://YOUR-SERVICE.onrender.com/slack/interactions

Wait for Slack to verify the events URL and save the changes. Use the actual service URL from Render.

Stop your local Python server and ngrok. In a new Slack message, ask:

Add a task to review the onboarding PR by Friday.
Remember that I prefer short updates with action items first.

The hosted agent should respond. Find that conversation in the production Control Plane's Sessions or inspect it in Traces.

Verify that your notes survive a deploy

In Render, open the web service and choose Manual DeployDeploy latest commit. Wait for it to become healthy, then start a new Slack message:

What's on my list, and how do I like my updates?

The agent should retrieve the task and preference from Postgres. You now have an agent you can use in Slack with your laptop closed.

Keep improving it

To change its behavior, edit the instructions in personal_agent.py, commit, and push. Render can deploy linked-branch changes automatically; check the service's Auto-Deploy setting. Review each deployment in Logs and test the updated behavior from Slack.

You can extend the agent with knowledge, additional tools, or scheduled tasks. For a larger platform with deployment scripts and built-in platform agents, explore AgentOS on Render.