Skip to main content

exemplar-harness-sdk

Python SDK for Exemplar: session ingest, long-term memory, skills, prompts, HITL, and Relay policy adapters for runtime agent SDKs.

Quick start covers Agno, OpenAI SDK, Google ADK, and Claude Agent SDK. More frameworks — see Framework extras. Relay policy adapters — see Relay policy and examples/relay/.

Related package: terminal CLI — exemplar-cli (docs, examples).

Contents

Install

pip install exemplar-harness-sdk

# One agent framework (pick what you use)
pip install "exemplar-harness-sdk[agno]"
pip install "exemplar-harness-sdk[openai]"
pip install "exemplar-harness-sdk[google-adk]"
pip install "exemplar-harness-sdk[claude-agent]"

# Everything
pip install "exemplar-harness-sdk[all]"
export EXEMPLAR_API_KEY="eis_your_org_api_key"

Licensed for non-commercial use only. Commercial use requires a separate license from Exemplar Dev LLC. See LICENSE.


Quick start

Pick your agent framework below. Each section shows session ingest, memory, skills, and prompts for that stack.

Reuse the same session_id for every turn in a conversation. Session helpers call Harness.ingest() for you (Google ADK: call ingest_adk_session after the run). Skills and prompts are shared platform APIs — wire them into your agent with the patterns below.

flowchart LR
  Agent[Your agent] --> Integration[SDK integration]
  Integration --> Harness[Harness.ingest]
  Harness --> API[Exemplar platform API]
  API --> Eval[Harness eval]

Agno

pip install "exemplar-harness-sdk[agno]"

Session ingest

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from exemplar_harness import Harness
from exemplar_harness.integrations.agno import harness_agno_post_hook

harness = Harness.from_env()
agent = Agent(
    name="support-bot",
    model=OpenAIChat(id="gpt-4o"),
    post_hooks=[
        harness_agno_post_hook(
            harness,
            session_id="sess-abc",
            agent_id="support-bot",
            source_app="my-app",
        )
    ],
)
agent.run("Summarize our refund policy.")

Relay policy (tool hooks)

Same Harness client — share agent_id / session_id with ingest. Full per-SDK demos: examples/relay/.

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from exemplar_harness import Harness
from exemplar_harness.integrations.agno import harness_agno_post_hook

harness = Harness.from_env(agent_id="support-bot")
relay = harness.relay(surface="agno", source_app="my-app")

def get_weather(city: str) -> str:
    """Return a short weather summary for the city."""
    return f"Sunny in {city}"

agent = Agent(
    name="support-bot",
    model=OpenAIChat(id="gpt-4o"),
    tools=[get_weather],
    tool_hooks=[relay.agno_tool_hook(session_id="sess-abc")],
    post_hooks=[
        harness_agno_post_hook(
            harness,
            session_id="sess-abc",
            agent_id="support-bot",
            source_app="my-app",
        )
    ],
)

Runnable example: examples/relay/agno.py

Memory

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from exemplar_harness import Harness
from exemplar_harness.integrations.agno import harness_agno_post_hook
from exemplar_harness.integrations.memory.agno import (
    make_agno_memory_helper,
    harness_agno_memory_hooks,
)

harness = Harness.from_env()
mem = make_agno_memory_helper(
    harness, user_id="user-123", session_id="sess-abc", app_id="my-app"
)
pre, post = harness_agno_memory_hooks(mem)

agent = Agent(
    name="support-bot",
    model=OpenAIChat(id="gpt-4o"),
    pre_hooks=[pre],
    post_hooks=[
        post,
        harness_agno_post_hook(harness, session_id="sess-abc", agent_id="support-bot"),
    ],
)
agent.run("What do you know about my formatting preferences?")

Live example: examples/live/agno_memory_demo.py

Skills

Install the skill folder for Agent Skills–compatible runtimes (SKILL.md + files). Prompt-injection frameworks can also pass skill.instructions (markdown body only).

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from exemplar_harness import Harness

harness = Harness.from_env()
skills = harness.skills()

# Folder-first: dest/<name>/SKILL.md (+ references/, scripts/, assets/)
skills.install(".agents/skills", names=["refund-policy"])

skill = skills.get("refund-policy")
agent = Agent(
    name="support-bot",
    model=OpenAIChat(id="gpt-4o"),
    instructions=[skill.instructions],
)
agent.run("Can a customer return an item after 20 days?")

Live example: examples/live/agno_skills_demo.py

Prompts

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from exemplar_harness import Harness

harness = Harness.from_env()
built = harness.prompts().build("support-summary", variables={"topic": "returns"})

system = next((m["content"] for m in built.messages if m["role"] == "system"), "")
user = next((m["content"] for m in built.messages if m["role"] == "user"), "")

agent = Agent(
    name="support-bot",
    model=OpenAIChat(id="gpt-4o"),
    instructions=[system] if system else None,
)
agent.run(user)

OpenAI SDK

pip install "exemplar-harness-sdk[openai]"

Session ingest

from openai import OpenAI
from exemplar_harness import Harness
from exemplar_harness.integrations.openai import HarnessOpenAICallback, sdk_chat_completion

harness = Harness.from_env()
callback = HarnessOpenAICallback(
    harness,
    session_id="sess-abc",
    agent_id="support-bot",
    source_app="my-app",
)
client = OpenAI()
sdk_chat_completion(
    harness,
    callback,
    client,
    model="gpt-4o",
    messages=[{"role": "user", "content": "Summarize our refund policy."}],
)

Memory

from openai import OpenAI
from exemplar_harness import Harness
from exemplar_harness.integrations.memory.openai import (
    make_openai_memory_helper,
    sdk_chat_completion_with_memory,
)

harness = Harness.from_env()
helper = make_openai_memory_helper(
    harness, user_id="user-123", session_id="sess-abc", app_id="my-app"
)
client = OpenAI()
sdk_chat_completion_with_memory(
    helper,
    client,
    model="gpt-4o",
    messages=[{"role": "user", "content": "What do you know about my formatting preferences?"}],
)

Live example: examples/live/openai_memory_demo.py

Skills

from openai import OpenAI
from exemplar_harness import Harness

harness = Harness.from_env()
skills = harness.skills()
skills.install(".agents/skills", names=["refund-policy"])

skill = skills.get("refund-policy")
client = OpenAI()
client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": skill.instructions},
        {"role": "user", "content": "Can a customer return an item after 20 days?"},
    ],
)

Live example: examples/live/openai_skills_demo.py

Relay policy

OpenAI Agents SDK (not Chat Completions) uses tool guardrails:

harness = Harness.from_env(agent_id="support-bot")
relay = harness.relay(surface="openai_agents", source_app="my-app")
# Agent(..., tool_input_guardrails=[relay.openai_tool_input(session_id=...)],
#            tool_output_guardrails=[relay.openai_tool_output(session_id=...)])

Runnable example: examples/relay/openai_agents.py

Prompts

from openai import OpenAI
from exemplar_harness import Harness
from exemplar_harness.integrations.openai import HarnessOpenAICallback, sdk_chat_completion

harness = Harness.from_env()
built = harness.prompts().build("support-summary", variables={"topic": "returns"})
callback = HarnessOpenAICallback(harness, session_id="sess-abc", agent_id="support-bot")
client = OpenAI()
sdk_chat_completion(
    harness,
    callback,
    client,
    model=built.model or "gpt-4o",
    messages=built.messages,
)

Google ADK

pip install "exemplar-harness-sdk[google-adk]"

Session ingest

import asyncio

from exemplar_harness import Harness
from exemplar_harness.integrations.google_adk import ingest_adk_session
from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types

harness = Harness.from_env()
session_id, app_name, user_id = "sess-abc", "my_app", "user-1"

agent = LlmAgent(
    model="gemini-2.5-flash",
    name="support_bot",  # must be a valid Python identifier
    instruction="Answer concisely.",
)
sessions = InMemorySessionService()


async def run_and_ingest() -> None:
    await sessions.create_session(app_name=app_name, user_id=user_id, session_id=session_id)
    runner = Runner(agent=agent, app_name=app_name, session_service=sessions)
    message = types.Content(role="user", parts=[types.Part(text="Summarize our refund policy.")])
    async for _ in runner.run_async(user_id=user_id, session_id=session_id, new_message=message):
        pass
    session = await sessions.get_session(app_name=app_name, user_id=user_id, session_id=session_id)
    ingest_adk_session(
        harness,
        session.model_dump(mode="json", exclude_none=True),
        session_id=session_id,
        agent_id="support-bot",
        source_app="my-app",
    )


asyncio.run(run_and_ingest())

Memory

from exemplar_harness import Harness
from exemplar_harness.integrations.memory.google_adk import (
    make_google_adk_memory_helper,
    prepare_user_message,
    record_session_turn_with_memory,
)

harness = Harness.from_env()
mem = make_google_adk_memory_helper(
    harness, user_id="user-123", session_id="sess-abc", app_id="my-app"
)

question = "What do you know about my formatting preferences?"
user_text = prepare_user_message(mem, question)
# ... run your ADK agent with user_text, capture model_response ...
# record_session_turn_with_memory(mem, user_message=question, model_response=model_response)

Live example: examples/live/google_adk_memory_demo.py

Skills

from exemplar_harness import Harness
from google.adk.agents import LlmAgent

harness = Harness.from_env()
skills = harness.skills()
skills.install(".agents/skills", names=["refund-policy"])

skill = skills.get("refund-policy")
agent = LlmAgent(
    model="gemini-2.5-flash",
    name="support_bot",
    instruction=skill.instructions,
)

Live example: examples/live/google_adk_skills_demo.py

Relay policy

harness = Harness.from_env(agent_id="support-bot")
relay = harness.relay(surface="adk", source_app="my-app")
agent = LlmAgent(
    model="gemini-2.5-flash",
    name="support_bot",
    tools=[...],
    before_tool_callback=relay.adk_before_tool(session_id="sess-abc"),
    after_tool_callback=relay.adk_after_tool(session_id="sess-abc"),
)

Runnable example: examples/relay/adk.py

Prompts

from exemplar_harness import Harness
from google.adk.agents import LlmAgent
from google.genai import types

harness = Harness.from_env()
built = harness.prompts().build("support-summary", variables={"topic": "returns"})

system = next((m["content"] for m in built.messages if m["role"] == "system"), "Answer concisely.")
user = next((m["content"] for m in built.messages if m["role"] == "user"), "")

agent = LlmAgent(model="gemini-2.5-flash", name="support_bot", instruction=system)
message = types.Content(role="user", parts=[types.Part(text=user)])
# pass `message` into Runner.run_async(...), then ingest_adk_session as above

Claude Agent SDK

pip install "exemplar-harness-sdk[claude-agent]"

Session ingest

import asyncio

from exemplar_harness import Harness
from exemplar_harness.integrations.claude_agent import HarnessClaudeAgentHandler

harness = Harness.from_env()
handler = HarnessClaudeAgentHandler(
    harness,
    session_id="sess-abc",
    agent_id="support-bot",
    source_app="my-app",
)
asyncio.run(handler.run_query("Summarize our refund policy."))

Memory

import asyncio

from exemplar_harness import Harness
from exemplar_harness.integrations.claude_agent import HarnessClaudeAgentHandler
from exemplar_harness.integrations.memory.claude_agent import (
    make_claude_agent_memory_helper,
    prepare_prompt,
    record_agent_result_with_memory,
)

harness = Harness.from_env()
handler = HarnessClaudeAgentHandler(harness, session_id="sess-abc", agent_id="support-bot")
mem = make_claude_agent_memory_helper(
    harness, user_id="user-123", session_id="sess-abc", app_id="my-app"
)


async def run() -> None:
    question = "What do you know about my formatting preferences?"
    prompt = prepare_prompt(mem, question)
    result, _ = await handler.run_query(prompt)
    record_agent_result_with_memory(mem, prompt=question, result=result)


asyncio.run(run())

Live example: examples/live/claude_agent_memory_demo.py

Skills

import asyncio

from exemplar_harness import Harness
from exemplar_harness.integrations.claude_agent import (
    HarnessClaudeAgentHandler,
    merge_claude_agent_options,
)

harness = Harness.from_env()
skills = harness.skills()
# Claude Code also discovers folders under .claude/skills via CLI install/pull
skills.install(".claude/skills", names=["refund-policy"])

skill = skills.get("refund-policy")
handler = HarnessClaudeAgentHandler(harness, session_id="sess-abc", agent_id="support-bot")


async def run() -> None:
    from claude_agent_sdk import ClaudeAgentOptions

    options = merge_claude_agent_options(
        handler,
        ClaudeAgentOptions(system_prompt=skill.instructions),
    )
    await handler.run_query("Can a customer return an item after 20 days?", options=options)


asyncio.run(run())

Live example: examples/live/claude_agent_skills_demo.py

Relay policy

from claude_agent_sdk import ClaudeAgentOptions

harness = Harness.from_env(agent_id="support-bot")
relay = harness.relay(surface="claude_sdk", source_app="my-app")
options = ClaudeAgentOptions(
    hooks=relay.claude_hooks(session_id="sess-abc"),
)

Runnable example: examples/relay/claude_sdk.py

Prompts

import asyncio

from exemplar_harness import Harness
from exemplar_harness.integrations.claude_agent import (
    HarnessClaudeAgentHandler,
    merge_claude_agent_options,
)

harness = Harness.from_env()
built = harness.prompts().build("support-summary", variables={"topic": "returns"})
system = next((m["content"] for m in built.messages if m["role"] == "system"), "")
user = next((m["content"] for m in built.messages if m["role"] == "user"), "")
handler = HarnessClaudeAgentHandler(harness, session_id="sess-abc", agent_id="support-bot")


async def run() -> None:
    from claude_agent_sdk import ClaudeAgentOptions

    options = merge_claude_agent_options(
        handler,
        ClaudeAgentOptions(system_prompt=system or None),
    )
    await handler.run_query(user, options=options)


asyncio.run(run())

Session ingest

Base helper: Harness.ingest() / framework helpers above.

Example 1 — Framework helper (Agno)

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from exemplar_harness import Harness
from exemplar_harness.integrations.agno import harness_agno_post_hook

harness = Harness.from_env()
agent = Agent(
    name="support-bot",
    model=OpenAIChat(id="gpt-4o"),
    post_hooks=[harness_agno_post_hook(harness, session_id="sess-abc", agent_id="support-bot")],
)
agent.run("What is the return window?")

Example 2 — Direct ingest (no framework)

from exemplar_harness import Harness

harness = Harness.from_env()
harness.ingest(
    "generic",
    session_id="sess-abc",
    event="turns",
    data={
        "turns": [
            {
                "input": "What is harness eval?",
                "output": "Automated judge over agent sessions.",
                "model": "gpt-4o",
            }
        ]
    },
    agent_id="my-agent",
    source_app="my-app",
)
Parameter Purpose
session_id Groups turns into one eval session
agent_id Agent id on the ingest body (agentId); set on Harness(..., agent_id=...) to also send X-Harness-Agent-Id on MCP tool calls
source_app Your application name
auto_judge_run Run harness judge after ingest (True / False / omit)

Memory

Base helper: harness.memory(...).

Search accepts search_mode (hybrid | semantic | keyword) and format (json | json_compact | markdown | toon). recall defaults to markdown and prefers the server-rendered body when present.

Example 1 — Add and recall

from exemplar_harness import Harness

harness = Harness.from_env()
memory = harness.memory(user_id="user-123", session_id="chat-abc", app_id="my-app")

memory.add("User prefers bullet-point answers.", memory_type="preference")
context = memory.recall("how should I format answers?", format="markdown")

Example 2 — Search modes and formats

results = memory.search(
    "formatting preferences",
    top_k=5,
    search_mode="hybrid",
    format="json",
)
envelope = memory.search_envelope("theme", format="toon", search_mode="hybrid")
# envelope.body → prompt injection; envelope.records → structured hits

listed = memory.list(limit=20)
record = memory.get(listed[0].memory_id)
memory.update(record.memory_id, content="User prefers numbered lists.")
memory.delete(record.memory_id)

Skills

Base helper: harness.skills().

Example 1 — Create and list

from exemplar_harness import Harness

harness = Harness.from_env()
skills = harness.skills()

record = skills.create(
    name="refund-policy",
    instructions="# Refund policy\n\nReturns within 30 days.\n\nSee [references/policy.md](references/policy.md).",
    description="Refund workflow",
    tags=["support"],
    files={"references/policy.md": "# Policy\n\n30-day returns.\n"},
)
items = skills.list(limit=20)

Example 2 — Get, search, and install

fetched = skills.get("refund-policy")  # by ID or unique name
hits = skills.search("refund", top_k=5)

# Materialize SKILL.md + supporting files for agent runtimes
skills.install(".agents/skills", names=["refund-policy"])

Prompts

Base helper: harness.prompts().

Example 1 — Create and run

from exemplar_harness import Harness

harness = Harness.from_env()
prompts = harness.prompts()

record = prompts.create(
    name="support-summary",
    title="Support summary",
    messages=[
        {"role": "system", "content": "Be concise."},
        {"role": "user", "content": "Summarize topic: {{topic}}."},
    ],
    variables=["topic"],
)
result = prompts.run("support-summary", variables={"topic": "returns"})
print(result["content"])

Example 2 — Build for your own agent framework

Fetch a stored prompt, substitute {{variables}} locally, and hand messages to LangGraph, OpenAI, Haystack, etc. Does not call Exemplar’s model runner.

built = prompts.build("support-summary", variables={"topic": "returns"})
# built.messages -> [{"role": "system", ...}, {"role": "user", ...}]
# built.model    -> default model from the registry (if set)
# pass built.messages into your framework / LLM client

Or reuse an already-fetched record (no second network call):

record = prompts.get("support-summary")
built = record.build(variables={"topic": "returns"})

Example 3 — List and get

listed = prompts.list(limit=20)
fetched = prompts.get("support-summary")  # by ID or unique name
hits = prompts.search("support", top_k=5)

HITL (human-in-the-loop)

Base helper: harness.hitl(). Lets an agent pause mid-workflow and wait for a human decision. Requests appear in the console under Agent Harness → HITL Approvals, where a reviewer approves, rejects, answers, or picks an option. Blocking wait uses polling; there are no webhooks.

Production reviewers should resolve requests in the console (or with reviewer-scoped credentials). Do not have the agent runtime self-approve via /respond with the same org API key — that pattern is demo-only.

Example 1 — Approval gate (create + wait in one call)

from exemplar_harness import Harness, HITLTimeoutError

harness = Harness.from_env(agent_id="deploy-agent")
hitl = harness.hitl()

try:
    result = hitl.ask(
        "Deploy build 1234 to production?",
        description="All checks green. Blast radius: payments service.",
        payload={"build": "1234", "service": "payments"},
        ttl_seconds=1800,   # server-side expiry
        timeout=1800,       # local wait budget (seconds)
        poll_interval=5,
    )
except HITLTimeoutError:
    result = None

if result and result.approved:
    deploy()
elif result and result.state == "rejected":
    print(f"Rejected: {result.response.comment}")

Example 2 — Free-text input and single choice

answer = hitl.ask("Which rollback strategy?", request_type="input")
print(answer.response.text)

choice = hitl.ask(
    "Pick a deployment region",
    request_type="select",
    options=["us-east-1", "eu-west-1"],
)
print(choice.response.option)

Example 3 — Non-blocking create, check later, cancel

request = hitl.request_approval("Rotate production credentials?")

status = hitl.get(request.request_id)   # non-blocking status check
if status.is_pending:
    hitl.cancel(request.request_id)     # e.g. the run was aborted

Example 4 — As a tool in any agent framework

Plain sync methods — wrap them in a tool function for LangChain, Agno, CrewAI, OpenAI, etc.

from langchain_core.tools import tool

@tool
def ask_human_approval(question: str) -> str:
    """Ask a human operator to approve or reject an action."""
    result = harness.hitl().ask(question, timeout=900)
    if result.approved:
        return "approved"
    return f"denied ({result.state}): {result.response.comment or 'no comment'}"

Relay policy

Base helper: harness.relay(surface=...). Runtime policy for agent tool calls — decide before execute, observe after. Surfaces: claude_sdk | adk | agno | openai_agents | langchain | langgraph | pydantic_ai | crewai | semantic_kernel.

Defaults to fail-closed (fail_open=False): if Relay is unreachable, decide/evaluate raise instead of allowing the tool. Pass fail_open=True only when you explicitly prefer availability over enforcement.

Index and run instructions: examples/relay/README.md.

HARNESS_EXAMPLES_SIMULATED=1 python -m examples.relay.run_all
HARNESS_EXAMPLES_SIMULATED=1 python -m examples.relay.run_all --list
EXEMPLAR_API_KEY=... python -m examples.relay.evaluate

Per-SDK examples

Surface Adapter Example
Agno relay.agno_tool_hook examples/relay/agno.py
Claude Agent SDK relay.claude_hooks examples/relay/claude_sdk.py
Google ADK relay.adk_before_tool / adk_after_tool examples/relay/adk.py
OpenAI Agents relay.openai_tool_input / openai_tool_output examples/relay/openai_agents.py
LangChain relay.langchain_middleware examples/relay/langchain.py
LangGraph relay.langgraph_middleware examples/relay/langgraph.py
Pydantic AI relay.pydantic_ai_hooks examples/relay/pydantic_ai.py
CrewAI relay.crewai_hooks / crewai_register examples/relay/crewai.py
Semantic Kernel relay.semantic_kernel_filter / semantic_kernel_register examples/relay/semantic_kernel.py

Hook-free evaluate

CI / preflight / custom runtimes — same Control + Enforcement stack, no SDK hooks:

from exemplar_harness import Harness
from exemplar_harness.relay import RelayDecision

harness = Harness.from_env(agent_id="support-bot")
relay = harness.relay(surface="agno", source_app="my-app")

verdict = relay.evaluate(
    tool_name="shell",
    arguments={"command": "rm -rf /tmp/x"},
    user_id="user_123",
)
if verdict.decision is RelayDecision.DENY:
    raise RuntimeError(verdict.reason)

relay.evaluate_path(path=".env")
relay.evaluate_bash(command="ls -la")

Runnable example: examples/relay/evaluate.py


CLI (separate package)

Skills, prompts, and memory are also available as a standalone terminal package — not bundled with this SDK:

PyPI exemplar-cli
Docs exemplar-cli/README.md
Examples examples/cli/README.md
pip install exemplar-cli
export EXEMPLAR_API_KEY="eis_your_org_api_key"
exemplar doctor

Advanced usage

One advanced pattern per offering. For full framework wiring, see examples/live/.

Session ingest — Session helper with auto judge

from exemplar_harness import Harness

harness = Harness.from_env()
session = harness.session(
    "sess-abc",
    agent_id="support-bot",
    source_app="my-app",
    auto_judge_run=True,  # run judge after each ingest through this session
)
session.ingest(
    "generic",
    event="turns",
    data={"turns": [{"input": "Hello", "output": "Hi!", "model": "gpt-4o"}]},
)

Memory — Generic hook in any agent loop

from exemplar_harness import Harness
from exemplar_harness.integrations.memory import MemoryHook

harness = Harness.from_env()
memory = harness.memory(user_id="user-123", session_id="chat-abc", app_id="my-app")
hook = MemoryHook(memory, recall_top_k=5, auto_add=False)

user_input = "What do you know about me?"
recall = hook.before_turn(user_input)  # prepend to system prompt
# ... run LLM ...
hook.after_turn(user_input, assistant_output)  # no-op unless auto_add=True

Skills — Install folders for agent runtimes

A skill is a directory rooted at SKILL.md (plus optional references/, scripts/, assets/). Install the whole folder for Cursor, Claude Code, ADK, Agno, Deep Agents, AG2, CrewAI, and similar agents — do not treat record.instructions as the full skill (that field is the markdown body only, useful for quick editor/MCP use).

Live skills demos also cover framework-native loaders:

from exemplar_harness import Harness

skills = Harness.from_env().skills()

# Materialize all active skills: dest/<name>/SKILL.md + supporting files
paths = skills.install(".agents/skills")

# Or one skill into Cursor project skills
skills.install(".cursor/skills", names=["refund-policy"])

CLI equivalent: exemplar skills install --all --dest .agents/skills (alias of pull).

Prompts — Publish, build for frameworks, or run inline

from exemplar_harness import Harness

prompts = Harness.from_env().prompts()

prompts.publish_version(
    "support-summary",
    messages=[
        {"role": "system", "content": "Be concise."},
        {"role": "user", "content": "Bullet summary for: {{topic}}."},
    ],
    change_notes="Use bullets",
)

# Hand off to your agent framework (local {{var}} substitution)
built = prompts.build("support-summary", variables={"topic": "returns"})

# Or execute via Exemplar without a stored prompt
inline = prompts.run_inline(
    messages=[
        {"role": "system", "content": "Be concise."},
        {"role": "user", "content": "Say hello."},
    ],
    model="openai/gpt-4o-mini",
)

Framework extras

Framework Extra Wire this
LangChain langchain make_langchain_callback_handlercallbacks=[handler]
LangGraph langgraph HarnessLangGraphHandler.make_graph_callback_handler()
Deep Agents deepagents HarnessDeepAgentsHandler.make_graph_callback_handler() / record_run
LiteLLM litellm register_litellm_handler + metadata={"session_id": ...}
OpenAI SDK openai HarnessOpenAICallback.on_completion
Anthropic SDK anthropic make_anthropic_middleware
Claude Agent SDK claude-agent HarnessClaudeAgentHandler.run_query
Portkey portkey HarnessPortkeyCallback.on_completion
Agno agno harness_agno_post_hookAgent.post_hooks
Haystack haystack HarnessHaystackHandler.run_and_record
LlamaIndex llamaindex register_llamaindex_handler
AutoGen autogen HarnessAutoGenHandler.on_agent_run_complete
AG2 ag2 HarnessAG2Handler.record_ask / record_chat_turn
CrewAI crewai make_crewai_listener
Google GenAI SDK google-genai instrument_google_genai_client
Google ADK google-adk ingest_adk_session
Pydantic AI pydantic-ai instrument_pydantic_ai_agent
Semantic Kernel semantic-kernel register_semantic_kernel_filter
smolagents smolagents harness_smolagents_step_callback

Matching memory helpers live under exemplar_harness.integrations.memory.*. Relay policy adapters: examples/relay/ (python -m examples.relay.run_all).

# List / run live demos
python -m examples.live.run_all --list
python -m examples.live.run_memory_demos --list
python -m examples.live.run_platform_demos --list
HARNESS_EXAMPLES_SIMULATED=1 python -m examples.live.run_memory_demos --only memory_agno
HARNESS_EXAMPLES_SIMULATED=1 python -m examples.live.run_platform_demos --only skills_openai
HARNESS_EXAMPLES_SIMULATED=1 python -m examples.relay.run_all

Reference

Optional install extras

Extra Module
langchain exemplar_harness.integrations.langchain
langgraph exemplar_harness.integrations.langgraph
deepagents exemplar_harness.integrations.deepagents
litellm exemplar_harness.integrations.litellm
openai exemplar_harness.integrations.openai
anthropic exemplar_harness.integrations.anthropic
claude-agent exemplar_harness.integrations.claude_agent
portkey exemplar_harness.integrations.portkey
agno exemplar_harness.integrations.agno
haystack exemplar_harness.integrations.haystack
llamaindex exemplar_harness.integrations.llamaindex
autogen exemplar_harness.integrations.autogen
ag2 exemplar_harness.integrations.ag2
crewai exemplar_harness.integrations.crewai
google-adk exemplar_harness.integrations.google_adk
google-genai exemplar_harness.integrations.google_genai
pydantic-ai exemplar_harness.integrations.pydantic_ai
semantic-kernel exemplar_harness.integrations.semantic_kernel
smolagents exemplar_harness.integrations.smolagents

Vercel AI SDK is not included in the Python package (TypeScript SDK path).

Envelope v1

Each ingest POSTs schemaVersion: 1 to POST /api/harness-ingest/v1/sessions with a sourceType and framework-native data payload. The Exemplar platform API maps envelopes to eval session turns. Harness judge runs use POST /api/harness-judge/v1/runs; per-turn session eval uses POST /api/harness-session-eval/v1/sessions/{sessionId}.

Download files

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

Source Distribution

exemplar_harness_sdk-0.2.22.tar.gz (144.0 kB view details)

Uploaded Source

Built Distribution

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

exemplar_harness_sdk-0.2.22-py3-none-any.whl (197.9 kB view details)

Uploaded Python 3

File details

Details for the file exemplar_harness_sdk-0.2.22.tar.gz.

File metadata

  • Download URL: exemplar_harness_sdk-0.2.22.tar.gz
  • Upload date:
  • Size: 144.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.2 CPython/3.12.4 Darwin/24.5.0

File hashes

Hashes for exemplar_harness_sdk-0.2.22.tar.gz
Algorithm Hash digest
SHA256 4fbcef2f192efd8cbd2924c4dc1ca9d3b61325fb3542bd7e29b9cb6e71d4b27e
MD5 5e5274626cd4cac59762bc55dce6b86b
BLAKE2b-256 e29854ea65d9a191d2603806ad18845d1fd4f8a5b822074ba92329dd9b344cf5

See more details on using hashes here.

File details

Details for the file exemplar_harness_sdk-0.2.22-py3-none-any.whl.

File metadata

File hashes

Hashes for exemplar_harness_sdk-0.2.22-py3-none-any.whl
Algorithm Hash digest
SHA256 41e50da8a5e6878854918fdd735ea37e0218c3da39105294fe8b14b92afa1092
MD5 2e755b03ebfa1a0c76b1e063fcd4da1f
BLAKE2b-256 96f76daf055dc08d045273ca0f264c715b585a29f4b29c5dbd37d69a2dcfe868

See more details on using hashes here.

Supported by

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