PromptisePromptise
Docs
GitHub
Promptise - AI Framework LogoPromptise

The foundation layer for agentic intelligence. Build, secure and operate autonomous AI systems with Promptise Foundry.

pip install promptise

[01] Foundry

  • MCPcast
  • The Promptise Agent
  • Reasoning Engine
  • MCP
  • Agent Runtime
  • Prompt Engineering
  • Execution Engine
  • Agent Identity

[02] Resources

  • Documentation
  • GitHub
  • Guides
  • Learning Paths
  • Questions

[03] Company

  • About
  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Subprocessors

© 2026 Promptise by Manser Ventures. All rights reserved.

Open source · Python

← Learning paths> Agentic Engineering with Promptise Foundry
Lesson 60 / 71
85%

How to Run, Debug and Deploy an AI Agent in Python

Run, debug and deploy a Python AI agent project with one command: a package.json-style manifest, live traces, a terminal UI, JSON logs and an API.

Beginner15 minObservabilityDeployment
All 71 lessons↓
  1. ✓What Is an AI Agent? Definition, How It Works, Examples
  2. ✓How to Build an AI Agent in Python (2026 Guide)
  3. ✓What Is an Agent Harness? Parts and How to Build One
  4. ✓System Prompt Best Practices for AI Agents in Python
  5. ✓Best LLM for AI Agents: Test and Switch Models in Python
  6. ✓AI Agent YAML: Define and Run an Agent From a Config File
  7. ✓Streaming LLM Responses with FastAPI: Tokens and Tool Calls
  8. ✓Claude AI Agent with MCP: Use Anthropic Models in Promptise
  9. ✓Gemini AI Agent with MCP: Use Google Models in Promptise
  10. ✓Azure OpenAI Agent with MCP: Use Deployments in Promptise
  11. ✓OpenRouter AI Agent with MCP: Many Models in Promptise
  12. ✓Ollama AI Agent with MCP: Run Local Models in Promptise
  13. ✓LLM Semantic Cache and Model Fallback in Python
  14. ✓What Is MCP (Model Context Protocol)? A Developer's Guide
  15. ✓What Is Tool Calling? LLM Function Calling Explained
  16. ✓MCP Tools vs Resources vs Prompts (With Python Examples)
  17. ✓How to Connect MCP Servers to Your AI Agent in Python
  18. ✓Build a Production MCP Server in Python (Step by Step)
  19. ✓MCP Transports: stdio vs Streamable HTTP vs SSE (Python)
  20. ✓FastAPI MCP Server: Turn Your FastAPI App into MCP Tools
  21. ✓OpenAPI to MCP: Turn Any REST API into an MCP Server
  22. ✓MCP Authentication in Python: API Keys, JWT and OAuth
  23. ✓Build an Authenticated MCP Server for Your AI Agent (Python)
  24. ✓MCP Security Best Practices: A Checklist for MCP Servers
  25. ✓Testing MCP Servers in Python: pytest Without a Live Server
  26. ✓Too Many MCP Tools? LLM Tool Selection, Measured
  27. ✓MCP Server Caching, Timeouts and Circuit Breakers in Python
  28. ✓MCP vs CLI for AI Agents: Tokens, Security, When to Use Each
  29. ✓AI Agent Audit Logging: Tamper-Evident Logs in Python
  30. ✓AI Agent Human in the Loop: Approve Tool Calls in Python
  31. ✓AI Agent Prompt Injection: How to Defend Against It
  32. ✓Build a Multi-Agent System in Python (and When Not To)
  33. ✓Context Engineering for AI Agents: Context Window Management
  34. ✓How to Deploy an AI Agent with Docker (2026 Guide)
  35. ✓LLM Tool Rate Limiting: Per-Client Limits for MCP Servers
  36. ✓MCP Long-Running Tasks: Background Jobs in Python
  37. ✓MCP Server Monitoring: Prometheus, OpenTelemetry and Logs
  38. ✓Python AI Agent Frameworks Compared: Which to Choose (2026)
  39. ✓Self-Improving AI Agent: Learn From Tool Failures in Python
  40. ✓AI Agent Identity: Authenticate Agents to MCP Servers
  41. ✓Code-Action Agents in Python: One Program vs 37 Tool Calls
  42. ✓Multi-Tenant AI Agents: Keep Each Customer's Data Apart
  43. ✓What Is Agentic RAG? How It Differs from Classic RAG
  44. ✓AI Agent Memory in Python: Short-Term and Long-Term
  45. ✓Agentic RAG in Python: Give Your AI Agent a Search Tool
  46. ✓AI Agent Reasoning Patterns in Python: 9 Patterns Tested
  47. ✓Plan-and-Execute Agents in Python: Beyond the ReAct Loop
  48. ✓Self-Modifying AI Agent in Python: Open Mode & Limits
  49. ✓CrewAI Alternatives: 7 Options and How to Migrate (2026)
  50. ✓Migrate from AutoGen: Agent Framework, Promptise and More
  51. ✓What Is an LLM Guardrail? Types, Examples and Limits
  52. ✓AI Agent Guardrails in Python: Block Injection, Redact PII
  53. ✓AI Agent Code Execution Sandbox: Run LLM Code Safely
  54. ✓AI Agent Production Checklist: What to Check Before Launch
  55. ✓Approval Fatigue: Auto-Approve Safe AI Agent Actions
  56. ✓What Is Human in the Loop AI? Approvals for AI Agents
  57. ✓AI Agent Notifications: Webhook and Slack Alerts in Python
  58. ✓AI Agent Observability: Trace Tool Calls, Tokens and Cost
  59. ✓AI Agent Stuck in a Loop? How to Detect and Stop It
  60. 60How to Run, Debug and Deploy an AI Agent in Python
  61. 61AI Agent Cost Tracking: Tokens and Cost per Run and User
  62. 62How to Evaluate AI Agents: Evals, LLM Judges and pass^k
  63. 63AI Agent Cost Control: Budgets That Stop Runaway Spend
  64. 64How to Test LLM Prompts and AI Agents in Python
  65. 65AI Agent Evals in CI: Run Them on Every Pull Request
  66. 66Autonomous AI Agent Runtime: Budgets, Crash Recovery, API
  67. 67Event-Driven AI Agents: Webhook, Cron and File Triggers
  68. 68Durable AI Agents: Crash Recovery and Safe Resume
  69. 69Deploy AI Agents in Production: Long-Running Python Agents
  70. 70What Is an AI Agent Framework? When You Need One
  71. 71LangGraph Alternatives: 7 Options and How to Migrate (2026)

Lessons in this path

  1. ✓What Is an AI Agent? Definition, How It Works, Examples
  2. ✓How to Build an AI Agent in Python (2026 Guide)
  3. ✓What Is an Agent Harness? Parts and How to Build One
  4. ✓System Prompt Best Practices for AI Agents in Python
  5. ✓Best LLM for AI Agents: Test and Switch Models in Python
  6. ✓AI Agent YAML: Define and Run an Agent From a Config File
  7. ✓Streaming LLM Responses with FastAPI: Tokens and Tool Calls
  8. ✓Claude AI Agent with MCP: Use Anthropic Models in Promptise
  9. ✓Gemini AI Agent with MCP: Use Google Models in Promptise
  10. ✓Azure OpenAI Agent with MCP: Use Deployments in Promptise
  11. ✓OpenRouter AI Agent with MCP: Many Models in Promptise
  12. ✓Ollama AI Agent with MCP: Run Local Models in Promptise
  13. ✓LLM Semantic Cache and Model Fallback in Python
  14. ✓What Is MCP (Model Context Protocol)? A Developer's Guide
  15. ✓What Is Tool Calling? LLM Function Calling Explained
  16. ✓MCP Tools vs Resources vs Prompts (With Python Examples)
  17. ✓How to Connect MCP Servers to Your AI Agent in Python
  18. ✓Build a Production MCP Server in Python (Step by Step)
  19. ✓MCP Transports: stdio vs Streamable HTTP vs SSE (Python)
  20. ✓FastAPI MCP Server: Turn Your FastAPI App into MCP Tools
  21. ✓OpenAPI to MCP: Turn Any REST API into an MCP Server
  22. ✓MCP Authentication in Python: API Keys, JWT and OAuth
  23. ✓Build an Authenticated MCP Server for Your AI Agent (Python)
  24. ✓MCP Security Best Practices: A Checklist for MCP Servers
  25. ✓Testing MCP Servers in Python: pytest Without a Live Server
  26. ✓Too Many MCP Tools? LLM Tool Selection, Measured
  27. ✓MCP Server Caching, Timeouts and Circuit Breakers in Python
  28. ✓MCP vs CLI for AI Agents: Tokens, Security, When to Use Each
  29. ✓AI Agent Audit Logging: Tamper-Evident Logs in Python
  30. ✓AI Agent Human in the Loop: Approve Tool Calls in Python
  31. ✓AI Agent Prompt Injection: How to Defend Against It
  32. ✓Build a Multi-Agent System in Python (and When Not To)
  33. ✓Context Engineering for AI Agents: Context Window Management
  34. ✓How to Deploy an AI Agent with Docker (2026 Guide)
  35. ✓LLM Tool Rate Limiting: Per-Client Limits for MCP Servers
  36. ✓MCP Long-Running Tasks: Background Jobs in Python
  37. ✓MCP Server Monitoring: Prometheus, OpenTelemetry and Logs
  38. ✓Python AI Agent Frameworks Compared: Which to Choose (2026)
  39. ✓Self-Improving AI Agent: Learn From Tool Failures in Python
  40. ✓AI Agent Identity: Authenticate Agents to MCP Servers
  41. ✓Code-Action Agents in Python: One Program vs 37 Tool Calls
  42. ✓Multi-Tenant AI Agents: Keep Each Customer's Data Apart
  43. ✓What Is Agentic RAG? How It Differs from Classic RAG
  44. ✓AI Agent Memory in Python: Short-Term and Long-Term
  45. ✓Agentic RAG in Python: Give Your AI Agent a Search Tool
  46. ✓AI Agent Reasoning Patterns in Python: 9 Patterns Tested
  47. ✓Plan-and-Execute Agents in Python: Beyond the ReAct Loop
  48. ✓Self-Modifying AI Agent in Python: Open Mode & Limits
  49. ✓CrewAI Alternatives: 7 Options and How to Migrate (2026)
  50. ✓Migrate from AutoGen: Agent Framework, Promptise and More
  51. ✓What Is an LLM Guardrail? Types, Examples and Limits
  52. ✓AI Agent Guardrails in Python: Block Injection, Redact PII
  53. ✓AI Agent Code Execution Sandbox: Run LLM Code Safely
  54. ✓AI Agent Production Checklist: What to Check Before Launch
  55. ✓Approval Fatigue: Auto-Approve Safe AI Agent Actions
  56. ✓What Is Human in the Loop AI? Approvals for AI Agents
  57. ✓AI Agent Notifications: Webhook and Slack Alerts in Python
  58. ✓AI Agent Observability: Trace Tool Calls, Tokens and Cost
  59. ✓AI Agent Stuck in a Loop? How to Detect and Stop It
  60. 60How to Run, Debug and Deploy an AI Agent in Python
  61. 61AI Agent Cost Tracking: Tokens and Cost per Run and User
  62. 62How to Evaluate AI Agents: Evals, LLM Judges and pass^k
  63. 63AI Agent Cost Control: Budgets That Stop Runaway Spend
  64. 64How to Test LLM Prompts and AI Agents in Python
  65. 65AI Agent Evals in CI: Run Them on Every Pull Request
  66. 66Autonomous AI Agent Runtime: Budgets, Crash Recovery, API
  67. 67Event-Driven AI Agents: Webhook, Cron and File Triggers
  68. 68Durable AI Agents: Crash Recovery and Safe Resume
  69. 69Deploy AI Agents in Production: Long-Running Python Agents
  70. 70What Is an AI Agent Framework? When You Need One
  71. 71LangGraph Alternatives: 7 Options and How to Migrate (2026)
← Path overview

An AI agent project needs more than agent code: the right environment variables, a way to see each step when an answer is wrong, production logs, and often an HTTP API. This guide shows how to do all of that for a Python agent with one command, promptise run, by building a small customer support agent and taking it from your laptop to a Docker container.

[01]

How do you run, debug and deploy a Python AI agent project?

Describe the project in a promptise.toml file (the main file, scripts and required environment), then run it with promptise run. Add --devtools to trace every LLM call and tool call, --tui for a terminal UI, --prod for JSON logs and a clean shutdown, and --serve for an authenticated HTTP API.

  • One manifest: promptise.toml works like package.json: main, [scripts], [env].

  • No code changes: your main file stays a normal Python script; every agent it builds is traced automatically.

  • Debugging: --devtools shows tools, arguments, results, tokens, latency and cost for each step.

  • Production: --prod adds JSON logs, checks before start and graceful shutdown; --serve adds health checks, invoke and streaming endpoints.

  • Version: everything here needs Promptise Foundry 1.4.1 or later.


[02]

What is promptise run?

promptise run is the project runner of Promptise Foundry, an open-source Python framework for AI agents. It reads a manifest, promptise.toml, that plays the role of package.json in a Node project:

npm

Promptise

---|---

package.json

promptise.toml (or [tool.promptise] in pyproject.toml)

"main": "index.js"

main = "main.py"

"scripts"

Text
[scripts]

npm start

promptise run

npm run dev

promptise run dev

npm init

promptise init --project

Your main file stays a normal Python program. promptise run runs it the way python main.py does, and adds the parts every agent project needs around it:

  • Environment: loads the .env files you list and checks required variables before anything starts.

  • Dev tools: --devtools prints every LLM call and tool call with tokens, latency and cost.

  • Terminal UI: --tui opens a full-screen view of the agent's chat, trace, tools, metrics, logs and approvals.

  • Production: --prod switches to JSON logs, checks the project before start and shuts down cleanly.

  • HTTP API: --serve puts your agent behind authenticated endpoints.

None of this needs changes to your agent code.

How it works

Text
1
2
3
4
5
6
7
8
9
promptise run [flags] [file | script]
  ├─ find promptise.toml (current directory and up)  → project root
  ├─ load [env] and check required variables         → stop with exit code 2 if anything is missing
  ├─ install the run's hook in build_agent()          → every agent the program builds is traced
  └─ run main.py as __main__
        ├─ --devtools  trace on stderr, summary at the end
        ├─ --tui       program in a child process, events streamed to the terminal UI
        ├─ --prod      JSON logs, SIGTERM → clean shutdown
        └─ --serve     agent factory behind /healthz, /readyz, /v1/invoke, /v1/stream
promptise run finds promptise.toml to set the project root, loads [env] and stops with exit code 2 if a required variable is missing, installs its hook in build_agent() so every agent is traced, and runs main.py as __main__, with --devtools, --tui, --prod or --serve choosing a trace on stderr, the terminal UI, JSON logs with a clean shutdown, or HTTP endpoints.
FigureWhat promptise run does before and while it runs your program

[03]

When to use promptise run (and when not to)

Use it when your agent is a project you run, debug and deploy: a script that builds an agent with build_agent(), a support bot, a background worker, an internal API. It gives every project the same commands, so a teammate can run yours with promptise run without reading a README.

You don't need it for a notebook experiment, or when the agent lives inside an existing web app that already has its own server, logging and deployment. In that case, call build_agent() from your app and use observability in code instead.


[04]

What you need

  • Python 3.10 or later

  • Promptise Foundry 1.4.1 or later (pip install -U "promptise>=1.4.1")

  • An API key for your model provider (this guide uses OPENAI_API_KEY with gpt-5-mini)

  • Docker, only for the last step


[05]

Step 1: Create a project

>_Terminal
promptise init --project support-bot
cd support-bot
cp .env.example .env    # then put your OPENAI_API_KEY in .env

promptise init --project creates a working project: promptise.toml, agent.py with the agent, main.py with the program, .env.example, a README.md and .gitignore entries for .env and the run reports. The rest of this guide uses a slightly larger version of that project: a support agent for an outdoor shop that looks up orders, searches help center articles and opens tickets for a person.


[06]

Step 2: Describe the project in promptise.toml

TOMLpromptise.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# The support bot's manifest: how `promptise run` runs this project.
# Reference: https://docs.promptise.com/core/projects/

name = "support-bot"
version = "0.1.0"
description = "Answers customer support tickets for a small online shop"
main = "main.py"                    # the program `promptise run` runs
agent = "agent.py:create_agent"     # the agent factory for --serve, -i and chat mode

[scripts]                           # `promptise run <name> [args]`, like `npm run`
dev = "promptise run --devtools --watch"
ui = "promptise run --tui"
chat = "promptise run --tui --mode chat"
start = "promptise run --prod"
serve = "promptise run --serve"
check = "promptise run --prod --check"

[env]
files = [".env"]                    # loaded in order; never overrides a variable already set
required = ["OPENAI_API_KEY"]
vars = { SUPPORT_BOT_MODEL = "openai:gpt-5-mini" }   # a default; set the variable to change it

[dev]                               # with --devtools, --tui and --watch
observe = "full"
watch = ["."]
report = ".promptise/last-run.json" # a JSON run report, written on exit

[prod]                              # with --prod
log_format = "json"
log_level = "INFO"
shutdown_timeout = 20

[serve]                             # with --serve
host = "127.0.0.1"
port = 8080
max_concurrency = 4

# USD per 1M tokens, for the cost estimates in --devtools and --tui.
# Check your provider's current prices before you rely on these numbers.
[pricing]
"gpt-5-mini*" = { input = 0.25, output = 2.0 }

What each part does:

  • `main` is the program promptise run runs. If you leave it out, main.py, agent.py or app.py is used, whichever exists.

  • `agent` points at a function that builds and returns the agent (an agent factory). You need it to chat with the agent, ask it one question from the command line, or serve it over HTTP.

  • `[scripts]` holds named commands, run with promptise run <name>.

  • `[env]` lists the .env files to load and the variables that must be set. A variable that is already set in your shell is never overwritten.

  • `[dev]` controls the dev tools: how much to record, what to watch, and where to write a run report.

  • `[prod]` and `[serve]` configure production logs, shutdown and the HTTP API.

  • `[pricing]` holds your model prices in USD per million tokens, for cost estimates. Promptise ships no price list, because prices change.

Unknown keys are errors, so a typo like mian = "main.py" stops the run with mian: unknown key instead of being ignored. The manifest holds no secrets: API keys and tokens come from the environment.


[07]

Step 3: Write the agent and the program

Put the agent in a factory function. promptise run calls it with a RunContext (project, mode, flags, the --model override), and your own code can call it without one:

Pythonagent.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""The support bot's agent: the factory and three local tools.

The tools read and write an in-memory shop, so the example needs no network
apart from the model itself.  ``main.py`` calls ``create_agent()``;
``promptise run`` calls ``create_agent(ctx)`` for ``--serve``, ``-i`` and chat
mode.
"""

from __future__ import annotations

import json
import os

from langchain_core.tools import tool
from promptise import PromptiseAgent, build_agent
from promptise.run import RunContext

DEFAULT_MODEL = "openai:gpt-5-mini"

INSTRUCTIONS = """\
You are the support agent of Trailhead, a small online outdoor shop.

- Before you say anything about an order, look it up with lookup_order.
- Answer policy questions (returns, refunds, shipping) from search_help_center,
  never from memory.
- Refunds and damaged items need a person: open a ticket with open_ticket and
  give the customer the ticket ID.
- Never invent order details. If an order ID is missing, ask for it.
- Be brief and friendly. Sign off as "Trailhead Support".
"""

ORDERS: dict[str, dict[str, str]] = {
    "A1001": {"item": "Rain jacket", "status": "delivered", "delivered_on": "2026-10-12"},
    "A1002": {
        "item": "Hiking boots",
        "status": "in transit",
        "carrier": "DHL",
        "expected_on": "2026-10-19",
    },
    "A1003": {"item": "Steel water bottle", "status": "delivered", "delivered_on": "2026-10-15"},
}

ARTICLES: dict[str, str] = {
    "Returns": (
        "Unworn items can be returned within 30 days of delivery. Start a return at "
        "trailhead.example.com/returns; the return label is free."
    ),
    "Refunds": (
        "Refunds go to the original payment method 3 to 5 business days after the "
        "returned item arrives. Damaged items are refunded without a return."
    ),
    "Shipping": (
        "Standard shipping takes 3 to 5 business days. The tracking link is in the "
        "shipping confirmation email."
    ),
}

TICKETS: list[dict[str, str]] = []
"""Tickets opened for a person (in memory; a real bot would call a help desk API)."""


@tool
def lookup_order(order_id: str) -> str:
    """Look up an order by its ID, for example A1002. Returns the item, status and dates."""
    key = order_id.strip().upper()
    order = ORDERS.get(key)
    if order is None:
        return f"No order {order_id!r}. Order IDs look like A1002."
    return json.dumps({"order_id": key, **order})


@tool
def search_help_center(query: str) -> str:
    """Search the help center articles (returns, refunds, shipping). Returns the best matches."""
    words = [w.strip(".,?!").lower() for w in query.split() if len(w) > 3]
    scored = []
    for title, text in ARTICLES.items():
        haystack = f"{title} {text}".lower()
        score = sum(word in haystack for word in words)
        if score:
            scored.append((score, title, text))
    if not scored:
        return "No article matches. Try other words, or open a ticket for a person."
    scored.sort(reverse=True)
    return "\n".join(f"{title}: {text}" for _, title, text in scored[:2])


@tool
def open_ticket(customer_email: str, summary: str, priority: str = "normal") -> str:
    """Hand a case to a person on the support team. Use it for refunds, damaged items and
    anything you cannot solve. priority is low, normal or high."""
    ticket_id = f"T-{len(TICKETS) + 1:04d}"
    TICKETS.append(
        {"id": ticket_id, "email": customer_email, "summary": summary, "priority": priority}
    )
    return (
        f"Opened {ticket_id} ({priority}) for {customer_email}. "
        "A person replies within one business day."
    )


async def create_agent(ctx: RunContext | None = None) -> PromptiseAgent:
    """Build the support agent.

    The model is the ``--model`` override when ``promptise run`` passes one,
    else ``SUPPORT_BOT_MODEL`` (a default in ``promptise.toml``), else
    ``openai:gpt-5-mini``.
    """
    model = (
        (ctx.model if ctx is not None else None)
        or os.environ.get("SUPPORT_BOT_MODEL")
        or DEFAULT_MODEL
    )
    return await build_agent(
        model=model,
        instructions=INSTRUCTIONS,
        extra_tools=[lookup_order, search_help_center, open_ticket],
    )

The program is an ordinary script. It builds the agent, answers the tickets in its inbox (or the one you pass), and shuts the agent down:

Pythonmain.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
"""The support bot's program: answer the tickets in the inbox, or the one you pass.

A normal Python script::

    python main.py                                  # the three sample tickets
    python main.py "Where is my order A1002?"       # one ticket

``promptise run`` runs it the same way and adds the project's environment,
dev tools, the terminal UI or production behavior, with no changes here::

    promptise run --devtools
    promptise run main.py "Where is my order A1002?"
"""

from __future__ import annotations

import asyncio
import sys

from agent import TICKETS, create_agent

INBOX = [
    "Hi, where is my order A1002? It was supposed to arrive by now.",
    "How do I return a jacket that doesn't fit?",
    "My order A1003 arrived dented. I'd like a refund please. I'm lee@example.com.",
]


async def main() -> None:
    tickets = [" ".join(sys.argv[1:])] if len(sys.argv) > 1 else INBOX
    agent = await create_agent()
    try:
        for number, ticket in enumerate(tickets, 1):
            print(f"--- Ticket {number}: {ticket}")
            result = await agent.ainvoke({"messages": [{"role": "user", "content": ticket}]})
            print(result["messages"][-1].content)
            print()
    finally:
        await agent.shutdown()
    if TICKETS:
        print(f"Handed to a person: {', '.join(t['id'] for t in TICKETS)}")


if __name__ == "__main__":
    asyncio.run(main())

python main.py works on its own. Nothing in either file depends on promptise run.


[08]

Step 4: Run the project

>_Terminal
promptise run main.py "Hi, where is my order A1002? It was supposed to arrive by now."
Output
--- Ticket 1: Hi, where is my order A1002? It was supposed to arrive by now.
Thanks — I looked up order A1002. It's for "Hiking boots" and is currently in transit with DHL. The expected delivery date is 2026-10-19 (today is 2026-10-17), so it should arrive by the 19th.

If you want me to open a ticket to investigate or follow up with DHL after the 19th, I can do that — would you like me to open one?

Trailhead Support

How it works:

1. promptise run looks for promptise.toml in the current directory and its parents, the way npm finds package.json, and treats that directory as the project root. 2. It loads [env]: your .env files, then the defaults in vars. 3. It checks the project: the manifest is valid, the main file exists, and every required variable is set. If something is wrong, it lists every problem at once and exits with code 2. 4. It runs main.py from the project root with your arguments in sys.argv, and exits with your program's exit code.

Two more commands help here. promptise run --check runs the checks without starting anything, which is useful in CI. promptise run --list prints the scripts:

Output
script  command                         
dev     promptise run --devtools --watch
ui      promptise run --tui             
chat    promptise run --tui --mode chat 
start   promptise run --prod            
serve   promptise run --serve           
check   promptise run --prod --check

To pass arguments to the main file, name the file first (promptise run main.py ARGS). A bare word after promptise run is read as a script name.


[09]

Step 5: Debug the agent with dev tools

When the agent gives a wrong answer, you need to see what it did: which tools it called, with which arguments, what came back, and how many tokens each step used. Add --devtools:

>_Terminal
promptise run --devtools main.py "Hi, where is my order A1002? It was supposed to arrive by now."
Output
promptise run support-bot · main.py · script · devtools on (observe full)
● agent  model openai:gpt-5-mini  3 tool(s)  0 MCP server(s)  observe full
--- Ticket 1: Hi, where is my order A1002? It was supposed to arrive by now.
▸ agent  Hi, where is my order A1002? It was supposed to arrive by now.
  ◆ llm gpt-5-mini-2025-08-07  1.44s  in 368 out 26 tok  $0.0001  → lookup_order
  ⚙ lookup_order({'order_id': 'A1002'})
  ✓ lookup_order 1ms  → {"order_id": "A1002", "item": "Hiking boots", "status": "in transit", "carrier": "DHL", "expected_on": "2026-10-19"}
  ◆ llm gpt-5-mini-2025-08-07  7.26s  in 442 out 711 tok  $0.0015
◂ agent done · 8.72s · 2 llm call(s) · 1 tool call(s) · 1547 tok
Thanks — I checked your order A1002. It's for Hiking boots, currently "in transit" with DHL and the expected delivery date is 2026-10-19.

If you'd like, I can open a support ticket to investigate with the carrier — want me to do that? 

Trailhead Support

■ agent shut down

promptise run · exit 0 · 9.1s · 2 llm call(s) · 1547 tok (in 810 out 737) · 1 tool call(s) · 0 
error(s) · cost $0.0017
agent  model              llm calls  tokens  tool calls  errors     cost
agent  openai:gpt-5-mini          2    1547           1       0  $0.0017
tool          calls  errors  avg ms
lookup_order      1       0       1
report: .promptise/last-run.json

How to read the trace, which goes to stderr while your program's output stays on stdout:

  • `● agent` is printed when the agent is built: its model, how many tools and MCP servers it has, and the observability level.

  • `▸ agent` marks a new request, with the user's message.

  • `◆ llm` is one model call: the model, its latency, input and output tokens, its estimated cost, and after → the tools the model asked for.

  • `⚙` is a tool call with its arguments, and `✓` or `✗` its result and latency.

  • `◂ agent done` closes the request with its totals.

  • The table at the end sums up LLM calls, tokens, tool calls, errors and cost per agent, per model and per tool.

What to look for: a tool called with wrong arguments means the tool's description or schema needs work. The same tool called again and again means the agent is stuck in a loop. A call with many input tokens means too much context. A slow model call is usually the one writing the final answer, and reasoning models count their reasoning as output tokens.

How it works: while promptise run runs your program, build_agent() asks it for settings before it builds each agent. It turns on observability for agents that set none, gives each agent a name, and sends the agent's events to the trace. Anything you set yourself wins. An agent built with observe=False stays unobserved, and an agent with its own observability settings keeps them. A plain promptise run without flags adds nothing.

Add --report run.json (or [dev] report) to save the whole run as JSON, which you can attach to a bug report or compare between runs.


[10]

Step 6: Restart on every change with --watch

>_Terminal
promptise run dev       # the dev script: promptise run --devtools --watch

--watch runs your program in a child process and restarts it whenever a Python, TOML, YAML, JSON or .env file in the project changes. Folders like .git, .venv, __pycache__ and node_modules are ignored. Use [dev] watch and [dev] ignore to change what is watched. When the program finishes on its own, the watcher waits for the next change instead of restarting it in a loop.


[11]

Step 7: Use the terminal UI

>_Terminal
promptise run --tui                 # run main.py in the UI (also -t or -tui)
promptise run --tui --mode chat     # chat with the agent from the factory

--tui opens a full-screen view of the run. Your program runs in a child process and its output is captured, so nothing it prints breaks the screen.

Key

Tab

What it shows

---|---|---

1

Chat / Console

The chat with the agent (answers stream in, tool calls inline), or your program's output with an input line for its stdin

2

Trace

Every LLM call and tool call of every agent, with the full details beside it

3

Tools

Each tool call's arguments, result and latency, and every tool each agent has

4

Metrics

Tokens, cost, latency, and totals per agent, model and tool

5

Events

Agent events such as slow tools, guardrail blocks and approvals

6

Approvals

Tool calls waiting for a person: a approves, d denies

7

Agents

Each agent's model, tools, MCP servers and features

8

MCP

The MCP servers and their tools

9

Logs

Python logs and stderr, filterable by level

0

Run

The project, the process, the environment (names only, never values) and the manifest

r restarts your program, s stops it, ? lists the keys and q quits. Combine it with --watch and the program restarts inside the UI on every save.

The Approvals tab is useful when your agent can do something risky, like issuing a refund. Give the agent an ApprovalPolicy with a QueueApprovalHandler for those tools, and each call waits in the tab until you approve or deny it. Human-in-the-loop approval for AI agents explains approval policies in detail. Screenshots of every tab are in the promptise run documentation.


[12]

Step 8: Automate with scripts

[scripts] works like npm scripts:

TOML
[scripts]
dev = "promptise run --devtools --watch"
eval = "python evals/run.py"
check = "promptise run --prod --check"
>_Terminal
promptise run eval smoke           # runs: python evals/run.py smoke
promptise run dev --model openai:gpt-5

Anything after the script name is added to the command. Flags like --model are passed on when the script is itself a promptise command, so promptise run dev --model openai:gpt-5 runs your dev setup on another model, and --model replaces the model of every agent your program builds. Scripts run from the project root, with your project's Python environment first on PATH, so python, pytest and promptise in a script are the ones from that environment.


[13]

Step 9: Ask the agent one question from the command line

For quick checks and CI jobs, -i builds the agent from the factory, asks one question and prints the answer:

>_Terminal
promptise run -i "How do I return a jacket that doesn't fit?" --json
Output
{"output": "You can return unworn items within 30 days of delivery. Start a return at trailhead.example.com/returns \u2014 the return label is free.\n\nWould you like me to start the return for you? If so, please share your order ID (or the email used for the order) and I\u2019ll help you from there.\n\nTrailhead Support", "error": null, "duration_ms": 8125.0, "usage": {"llm_calls": 2, "prompt_tokens": 783, "completion_tokens": 806, "total_tokens": 1589, "tool_calls": 1, "tool_errors": 0, "errors": 0, "retries": 0, "cost_usd": 0.0018077500000000001, "unpriced_models": [], "latency_p50_ms": 4353.9, "latency_p95_ms": 4353.9}}

--json adds the token usage and cost, and -i - reads the question from stdin. The exit code is 0 when the agent answered and 1 when it failed, so a CI step can depend on it. Without -i, promptise run agent.py opens an interactive chat with /stats, /tools and /reset commands.


[14]

Step 10: Run the agent in production

>_Terminal
promptise run --prod

--prod changes three things:

  • Logs are JSON, one object per line on stderr, ready for Datadog, Grafana Loki, CloudWatch or any log pipeline. Your program's stdout is untouched.

  • Checks fail fast. If a required variable is missing, the run logs one preflight failed line listing every problem and exits with code 2, before any agent is built.

  • SIGTERM shuts down cleanly. When your orchestrator stops the container, the program gets the same signal as Ctrl+C: finally blocks run, agents close their MCP connections, and the process exits with 143.

To log each agent step too, set [prod] observe = "basic" (or pass --observe basic). Here are the log lines of one run, filtered with jq:

>_Terminal
promptise run --prod --observe basic main.py "Where is A1003?" 2>&1 >/dev/null \
  | jq -c 'select(.logger == "promptise.run.events") | {msg, agent, event: .entry.event_type} | del(..|nulls)'
Output
{"msg":"run.start"}
{"msg":"agent.built","agent":"agent"}
{"msg":"timeline","agent":"agent","event":"agent.input"}
{"msg":"event","agent":"agent"}
{"msg":"timeline","agent":"agent","event":"tool.call"}
{"msg":"timeline","agent":"agent","event":"tool.result"}
{"msg":"timeline","agent":"agent","event":"agent.output"}
{"msg":"event","agent":"agent"}
{"msg":"agent.closed","agent":"agent"}
{"msg":"run.exit"}
{"msg":"stats"}

The last line of every run carries its totals (LLM calls, tokens, tool calls and cost), so you can chart cost per run from your logs.


[15]

Step 11: Serve the agent as an HTTP API

>_Terminal
export PROMPTISE_SERVE_TOKEN="a-long-random-secret"
promptise run --serve --port 8765

--serve builds the agent from the factory and serves it:

Endpoint

What it does

---|---

GET /healthz

Liveness: the process is up

GET /readyz

Readiness: the agent is built and accepting requests

GET /v1/info

The project, model and tools

POST /v1/invoke

Ask the agent; returns the answer and token usage

POST /v1/stream

Ask the agent; streams tokens and tool calls as server-sent events

>_Terminal
curl -s -X POST localhost:8765/v1/invoke \
  -H "Authorization: Bearer $PROMPTISE_SERVE_TOKEN" -H "Content-Type: application/json" \
  -d '{"input": "Where is my order A1002?"}'
Output
{"output":"Your order A1002 (Hiking boots) is in transit with DHL and is expected to arrive on 2026-10-19. \n\nIf you want me to look up tracking details or check further, tell me and I’ll help.\n\nTrailhead Support","duration_ms":6462.2,"usage":{"llm_calls":2,"prompt_tokens":790,"completion_tokens":408,"total_tokens":1198},"request_id":"9ae9deb1430f426c83fcd75e1130c17c"}

Requests to /v1/* need the bearer token from the variable [serve] auth_token_env names. Pass a session_id to keep a conversation going when your agent has a conversation store. When the server is stopped, it answers new requests with 503, lets running requests finish, and exits with code 0.

To run it in Docker:

Dockerfile
1
2
3
4
5
6
7
8
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir "promptise>=1.4.1"
# Configuration comes from the container's environment, not from a .env file.
# Set OPENAI_API_KEY and PROMPTISE_SERVE_TOKEN when you start the container.
ENV PROMPTISE_NO_DOTENV=1
CMD ["promptise", "run", "--prod", "--serve", "--host", "0.0.0.0", "--port", "8080"]

[16]

Common problems and fixes

Symptom

Cause

Fix

---|---|---

no script or file named 'hello'

A bare word after promptise run is read as a script name

Name the main file first: promptise run main.py hello

missing required environment variable(s): OPENAI_API_KEY

The variable is not in your shell or in the .env files listed under [env] files

Add it to .env (copy .env.example), or export it

... is an agent built at import time

agent = await build_agent(...) at module level: the agent needs a running event loop

Build it in a factory, async def create_agent(ctx=None), and set agent = "agent.py:create_agent"

mian: unknown key (check the spelling)

A typo in promptise.toml

Fix the key; unknown keys are always errors

Cost shows —

The model has no entry in [pricing]

Add "model-name*" = { input = ..., output = ... } in USD per million tokens

refusing to serve on 0.0.0.0 without an auth token

Serving on a network address with no bearer token

Set PROMPTISE_SERVE_TOKEN (or the variable [serve] auth_token_env names)

--tui fails in CI

The terminal UI needs an interactive terminal

Use --check, --devtools, --report or -i --json in CI

The container uses an old key

A .env file was copied into the image

Set PROMPTISE_NO_DOTENV=1 and pass configuration through the container's environment

An agent shows no trace

It was built with observe=False, which promptise run respects

Remove observe=False, or set your own observe level


[17]

Best practices

  • Keep one agent factory per project and use it everywhere: in main.py, in tests, and in promptise run --serve. Then the agent you debug is the agent you deploy.

  • Add a check script (promptise run --prod --check) and run it in CI, so a missing variable or a broken manifest fails the build instead of the deployment.

  • Fill in [pricing] for the models you use, so the cost shows up while you develop, not on your invoice.

  • Save a run report ([dev] report) when you reproduce a bug, and compare the tool calls between a good run and a bad one.

  • Use --model to try the same project on another model before you change any code.


[18]

Limitations

  • promptise run runs one process. Scaling, TLS and routing stay with your platform (Kubernetes, Cloud Run, a load balancer).

  • Serve mode has one bearer token, not per-user accounts. Put it behind your own gateway when users authenticate.

  • Costs are estimates from your [pricing] table, not your provider's invoice.

  • The terminal UI needs an interactive terminal.


[19]

FAQ

How do I run a Python AI agent project?

Describe it in a promptise.toml with a main file, then run promptise run from anywhere in the project. It loads your environment, checks the project, and runs the main file like python main.py. promptise init --project creates a project to start from.

How do I debug an AI agent in Python?

Run it with promptise run --devtools. You see every model call with its tokens, latency and cost, every tool call with its arguments and result, and a summary at the end. For a full-screen view with a trace you can browse, use promptise run --tui.

How do I see the token usage and cost of my agent?

--devtools prints the tokens and estimated cost of each LLM call and the totals per agent and model. -i --json returns them with the answer, --serve returns them in each /v1/invoke response, and --prod logs them at the end of every run. Add your prices to [pricing] for the cost.

Do I have to change my agent code to use promptise run?

No. Your main file is a normal Python script, and the dev tools work by hooking into build_agent() while promptise run is running. You only need an agent factory for chat mode, -i and --serve.

How do I deploy an AI agent as an API?

Run promptise run --prod --serve with a bearer token in the environment. It exposes health and readiness checks, an invoke endpoint and a streaming endpoint, and drains running requests on shutdown. Deploy AI agents in production covers the rest of a production setup.

Does promptise run work with MCP servers?

Yes. MCP servers you pass to build_agent() work as usual, and their tool calls appear in the dev tools, the Trace and Tools tabs, and the MCP tab. Connect MCP servers to an AI agent shows how to add them.


[20]

Next steps

  • Gate risky tool calls with human-in-the-loop approval, then answer them from the TUI's Approvals tab.

  • Give the agent real tools with MCP servers.

  • Learn what to record in production in AI agent observability.

  • Put a ceiling on spend with AI agent cost control.

  • Catch regressions before you deploy with AI agent evaluation in Python.

  • Plan the rest of the rollout with deploying AI agents in production.

← PreviousAI Agent Stuck in a Loop? How to Detect and Stop ItNext lesson →AI Agent Cost Tracking: Tokens and Cost per Run and User