An agent
Answer questions, call tools or guide a user through a workflow.
See where your code runs and how the platform handles a request.
Three ways to add your business logic to the platform.
Answer questions, call tools or guide a user through a workflow.
Give users a dedicated screen and connect agents to your business API.
Keep a team’s document library up to date from an external source.
Start with the user’s task, then choose what you need to build.
A pod is a service you run; it can start locally as a Python process.
Your agent executes in its pod. Knowledge Flow manages the documents.
A managed agent instance is an agent configured for one team.
The UI asks the Control Plane to resolve the instance, its settings and its runtime URL.prepare-execution
The UI sends the message with the user token and team context.
The agent pod verifies access through OpenFGA.
The runtime runs your agent: model calls, tool calls or graph steps.
Tools can reach business services and retrieve documents.
The pod sends events back to the UI over the HTTP connection.
SSE means Server-Sent Events: progress and answer updates.
The Control Plane prepares the request. The runtime checks access and executes it.
Begin with the SDK; learn the infrastructure as your application needs it.
| You write | Fred provides | Python entry point |
|---|---|---|
| Agent instructions + tools | Typed authoring APIs and tool integration | fred-sdk[agents] |
| Graph state + steps | Workflow execution, checkpoints and human confirmation support | fred-sdk[agents]fred-runtime |
| Registry + configuration | Agent HTTP service, streaming and connections to platform services | fred-runtime[app] |
| Document sync handler | Knowledge Base contracts and integration with scheduled runs | fred-sdk[knowledge-base] |
Underneath: fred-pod handles configuration and workload identity;fred-core provides shared infrastructure for agents and platform services.
You own business behavior. Fred supplies the execution and integration framework.
Write a small Python agent, talk to it locally, then make it available to a team.
A minimal equivalent of the sample assistant, using the SDK authoring API.
from fred_sdk import ReActAgent
class Assistant(ReActAgent):
agent_id: str = "fred.samples.assistant"
role: str = "General-purpose assistant"
description: str = "Answers general questions."
system_prompt_template: str = (
"Answer clearly. Say when you are uncertain."
)
agent = Assistant()
REGISTRY = {agent.agent_id: agent}This first agent needs a configured model, with no external tools.
The app factory exposes your registry as an HTTP service.
from fred_runtime.app import (
create_agent_app,
load_agent_pod_config,
)
from fred_samples_agents.registry import REGISTRY
app = create_agent_app(
registry=REGISTRY,
config=load_agent_pod_config(),
)Same factory used by the sample’s main.py.
cd ~/Fred/fred-samples/agents
cp -n config/env.template config/.env
# Set OPENAI_API_KEY to your Mistral key
make runPython 3.12; sibling fred and fred-samples checkouts. The Makefile installs the local SDK/runtime dependencies.
The sample config listens on port 8010, under /samples/agents/v1, with user authentication disabled for local development.
You can try the assistant before connecting the pod to the Fred UI.
The CLI is a client of the same runtime API. Keep the pod running in another terminal.
make cli
/agents
/agent fred.samples.assistant
Explain what an API is.Run from fred-samples/agents.
The slash commands are entered inside the CLI.
curl -N \
http://127.0.0.1:8010/samples/agents/v1/agents/execute/stream \
-H 'Content-Type: application/json' \
-d '{
"agent_id": "fred.samples.assistant",
"input": "Explain what an API is.",
"session_id": "demo-01",
"runtime_context": {"user_id": "demo"}
}'-N displays SSE events as they arrive.
Reuse session_id to continue the conversation.
Direct agent IDs are useful for local tests; the Fred UI uses managed instances.
The Python definition becomes a discoverable template; a team enrolls an instance.
The operator configures the runtime catalog source and its browser-facing route.
The Control Plane reads the pod’s /agents/templates endpoint.
The catalog identifies the source runtime and agent definition.
An authorized user enrolls the template for a team and configures its settings.
The UI selects that instance. The runtime checks team access and resolves
the definition and settings before execution.
agent_id
The definition registered in Python
agent_instance_id
The configured agent owned by a team
One agent definition can serve multiple configured team instances.
Connect business operations and control how the work gets done.
The model chooses when to call it. Python performs the conversion.
from fred_sdk import ReActAgent, ToolContext, ToolOutput, tool
@tool("acme.units.to_metres", description="Convert km to metres.")
async def to_metres(ctx: ToolContext, km: float) -> ToolOutput:
return ctx.text(f"{km * 1000:g} metres")
class UnitsAgent(ReActAgent):
agent_id: str = "acme.units.assistant"
role: str = "Unit conversion assistant"
description: str = "Converts distances using a Python tool."
system_prompt_template: str = "Use the tool for conversions."
tools = (to_metres,)
agent = UnitsAgent()
REGISTRY = {agent.agent_id: agent}
Typed arguments describe what the model can pass.
Instructions guide the model; tools lists what it can call.
The pod serves this registry through create_agent_app.
You write the function and instructions. Fred runs the tool-calling loop.
MCP is a protocol for discovering tools and invoking them across a service boundary.
Declares which MCP servers it needs.
Connects to the configured servers and invokes tools.
Exposes business operations over HTTP.
# Inside the BankTransferGraphAgent definition:
default_mcp_servers: tuple[MCPServerRef, ...] = (
MCPServerRef(id="mcp-bank-core-demo"),
MCPServerRef(id="mcp-risk-guard-demo"),
)The bank sample calls account, risk and transfer tools.
Server IDs refer to configured connections; the declaration does not start the servers.
A local @tool runs in the agent pod. An MCP tool runs in a separate service.
Keep the same tool concept while choosing where the implementation runs.
ReAct lets the model choose tool calls. A graph defines the allowed steps and transitions.
workflow = GraphWorkflow(
entry="classify",
nodes={
"classify": classify_step,
"greet": greet_step,
"answer": answer_step,
"finalize": finalize_step,
},
edges={"greet": "finalize", "answer": "finalize"},
routes={"classify": {
"greeting": "greet",
"question": "answer",
}},
)Workflow excerpt from hello_graph/graph_agent.py.
State: a Pydantic model shared by steps.
Node: an async Python function.
Result: state updates + a route key.
You control the workflow; individual steps can still use a model.
Human-in-the-loop (HITL) makes a user decision part of the workflow.
choice_id = await choice_step(
context,
stage="transfer_confirmation",
title="Confirm Transfer",
question=question,
choices=[
HumanChoiceOption(id="confirm", label="Confirm"),
HumanChoiceOption(id="cancel", label="Cancel"),
],
)
return StepResult(
route_key="confirmed" if choice_id == "confirm"
else "cancelled"
)Simplified confirmation node body from the bank transfer sample.
The bank sample also asks for risk approval when the risk is elevated.
Bring a dedicated interface, a business API and agent tools together.
A person uses your interface. An agent calls your MCP tools. Your service owns the records.
Example: progress-tracker — FastAPI + SQLite + an MCP endpoint.
* Both API paths check the user’s identity and team access; the iframe receives no Fred token.
Keep business rules in your API, shared by the interface and the agent tools.
The iframe SDK lets your page ask its host for context, navigation and API requests.
import { createFredApplicationClient }
from "@fred-oss/iframe-sdk";
const fred = createFredApplicationClient({
hostOrigin: "https://fred.example",
applicationId: "progress-tracker",
});
await fred.connect();
const response = await fred.request("tasks");
if (!response.ok) throw new Error("Request failed");
const tasks = await response.json();Set hostOrigin to your actual Fred origin.
The host supplies the application and team route.
@fred-oss/iframe-sdkFramework-independent communication with the Fred host.
@fred-oss/uiReusable React components for your interface.
@fred-oss/design-tokensShared colors, typography tokens and optional fonts.
The host handles Fred credentials. Your iframe receives context and API responses.
The current samples keep the interface, API and tools around the same service.
Tag the API routes agents may call. Untagged routes remain available to the UI.
Expose /mcp and add its server ID to the runtime catalog.
Enable the application and the MCP capability for the team as separate choices.
# Progress Tracker: the same API serves both entry points
REST: /teams/{team_id}/tasks
MCP: /mcp
Application grant: app__progress-tracker
MCP capability: mcp-progress-trackerThe API validates the caller and team access for both people and agents.
The two sample applications make different choices about writes and storage.
| Document Triage | Progress Tracker | |
|---|---|---|
| User task | Review documents and record a decision | Track tasks, notes and decisions |
| Agent role | Read the board and propose triage | Read and update task records |
| Who writes? | The person, through the application | People and agent tools, through the API |
| Storage | Team workspace in Knowledge Flow | Application-owned SQLite database |
| Agent access | Fred’s platform document tools | MCP with user or delegated identity |
A third sample, Review Board, adds a staged agent workflow and application-owned OpenSearch.
Choose the write and storage model before implementing the interface.
Keep a library up to date and let agents retrieve the information they need.
One service manages the documents; a connector keeps their source in sync.
Receives documents, processes their content and indexes it for retrieval.
Manages the libraries and document lifecycle used by Fred.
Reads an external source and publishes its changes to a target library.
You write the source-specific synchronization logic.
Examples: a local folder, a Git repository or a WebDAV share. Knowledge Base authoring is currently beta.
The connector supplies documents. Knowledge Flow makes them available for retrieval.
Ingestion happens when content changes. Retrieval happens when a question needs it.
Upload or source synchronization
Process content and build indexes
Documents available for retrieval
Query with the current access context
Content and source references
Use the retrieved evidence to answer
Retrieval supplies context to the model; it does not train the model on your documents.
Inside a synchronization handler, write to the library assigned to the run.
async with DocumentPublisher(
PodConfiguration.load(),
library_id=context.library_id,
source_tag="fred",
) as publisher:
handle = await publisher.publish(
relative_path="handbook.md",
content=b"# Handbook\nWelcome to the team.",
version="v1",
)
outcome = await publisher.wait(handle.task_id)
if not outcome.succeeded:
raise RuntimeError("Document ingestion failed")Handler excerpt using fred_sdk.knowledge_base.PodConfiguration comes from its configuration module.
A successful upload is not yet proof that ingestion has completed.
Understand the synchronization loop before connecting a remote source.
cd ~/Fred/fred-samples/knowledge-bases/local-folder
make declaration
CONFIG_FILE=/nonexistent ENV_FILE=/nonexistent \
make sync ROOT=/path/to/notesWithout Fred connection configuration, the sample logs what it would publish or retract.
A connected pod needs workload identity and a target library. The offline scan does not ingest documents.
Discover the source files.
Compare content hashes with its ledger.
Publish new and changed files.
Retract confirmed deletions explicitly.
If the scan is incomplete, missing files are not treated as deletions.
Keep source synchronization reliable; let Knowledge Flow own document processing.
fred-deployment-factory runs the whole platform on your machine, in two ways.
Both run the same infrastructure: Keycloak, PostgreSQL, OpenSearch, OpenFGA, Temporal and S3 storage.
| Docker Compose | k3d | |
|---|---|---|
| Purpose | Debug one application fast | Deploy as production does |
| Infrastructure | Containers on your host: make docker-up | A local Kubernetes cluster: make k3d-up |
| Your code | A process from your checkout: make run | Your images and Helm chart: make k3d-app |
| Change loop | Edit, restart, set a breakpoint | Rebuild and roll out; rerun to converge |
| Identities | Fixed local defaults | Declared by each application |
Run one mode at a time: both use the same host ports.
Debug in Docker; prove it in k3d before you ship.
The infrastructure runs in containers; Fred and your pods run as local processes.
# fred-deployment-factory: the infrastructure
make docker-up
# fred: the four Fred services
make setup-env # once: .env files, model key
make run # Ctrl+C stops all fourFirst time: make bootstrap-local in apps/control-plane-backend makes you platform admin.
make docker-stop and make docker-start pause and resume without losing data.
Fast: a code change is a process restart, not an image build.
Debuggable: breakpoints, logs in your terminal, one service at a time with make run-fred-agents.
Real services: the same Keycloak, OpenFGA and Temporal as the cluster, not mocks.
Use Docker to find the bug; it is not a deployment.
Every application is deployed with its own Helm chart, in a local Kubernetes cluster.
The infrastructure, plus logs, events and metrics collection
Fred's chart with the production posture
Your application, next to Fred
../fred-agent-evaluator, ../fred-samples/knowledge-bases/webdav.What works on k3d has met the real chart, identities and permissions.
Your repository carries its own deployment; the factory names no application.
helmfile.yaml.gotmpl your releases: chart + values
values.yaml what k3d decides
identities.yaml your service clients
build your images
prepare, finish before and after the syncOnly the helmfile is required. make k3d-app-validate lints and renders without touching the cluster.
clients:
- id: my-app-worker
secret: MY_APP_CLIENT_SECRET
grants: [app/service_agent]secret names a key of fred-secrets. The factory generates its value once, creates the Keycloak client and grants its roles. Your values read the secret by secretKeyRef.
You declare what your application needs; the platform decides how to provide it.
The k3d stack collects every pod's logs, the Kubernetes events, metrics and workflows.
make k3d-health
bin/k3d-observe trace <id>
bin/k3d-observe logs '<query>'
bin/k3d-observe kpihealth: restarts and why, warnings, errors and HTTP 5xx per service. trace: every line naming a run, document or workflow.
Fred localhost:8088
Grafana localhost:3002 · Prometheus localhost:9090
OpenSearch Dashboards localhost:5601
Temporal UI localhost:8233
Read the collected evidence before reading pod consoles.
Clone them side by side, in the same parent folder: the commands in this deck assume it.
The four Fred services, the SDK and runtime you build on, the frontend, and Fred's Helm chart.
make setup-env
make runSample agents, applications, MCP servers and Knowledge Bases: the code shown in this deck.
cd agents
make runThe infrastructure with Docker Compose or k3d, and make k3d-app for any application.
make k3d-up
make k3d-app DIR=../fredStart from a sample, debug in Docker, prove it on k3d.