Part 1 / 6

Understand Fred

See where your code runs and how the platform handles a request.

Build with Fred

What you can build with Fred

Three ways to add your business logic to the platform.

Conversation + action

An agent

Answer questions, call tools or guide a user through a workflow.

Example: bank transferValidate a request and ask for confirmation before acting.
Interface + service

An application

Give users a dedicated screen and connect agents to your business API.

Example: progress trackerManage tasks through a web interface and a conversation.
Documents + synchronization

A Knowledge Base

Keep a team’s document library up to date from an external source.

Example: local folderSynchronize Markdown documents for agents to retrieve.

Start with the user’s task, then choose what you need to build.

Architecture

The main parts of Fred

A pod is a service you run; it can start locally as a Python process.

Fred UITeams, chat, apps Control PlaneInstances, settings, permissions Configure / prepare Your agent podPython agent + Fred runtimeChecks access, runs the turn Chat over HTTP / SSE Model provider Tools + servicesPython / MCP / business APIs Knowledge FlowIngest, index, retrieve Retrieve Your Knowledge Base podReads a folder, Git or WebDAV Synchronize source documents

Your agent executes in its pod. Knowledge Flow manages the documents.

Follow one request

What happens when you send a message?

A managed agent instance is an agent configured for one team.

01

Prepare

The UI asks the Control Plane to resolve the instance, its settings and its runtime URL.
prepare-execution

02

Check access

The UI sends the message with the user token and team context.
The agent pod verifies access through OpenFGA.

03

Execute

The runtime runs your agent: model calls, tool calls or graph steps.
Tools can reach business services and retrieve documents.

04

Stream the result

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.

Developer responsibilities

Your code, Fred’s responsibilities

Begin with the SDK; learn the infrastructure as your application needs it.

You writeFred providesPython entry point
Agent instructions + toolsTyped authoring APIs and tool integrationfred-sdk[agents]
Graph state + stepsWorkflow execution, checkpoints and
human confirmation support
fred-sdk[agents]
fred-runtime
Registry + configurationAgent HTTP service, streaming and
connections to platform services
fred-runtime[app]
Document sync handlerKnowledge 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.

Part 2 / 6

Run your first agent

Write a small Python agent, talk to it locally, then make it available to a team.

Your first agent

An agent starts with a Python definition

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.

Your first agent

Run the sample pod locally

The app factory exposes your registry as an HTTP service.

The application entry point
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.

Start the shipped samples
cd ~/Fred/fred-samples/agents
cp -n config/env.template config/.env
# Set OPENAI_API_KEY to your Mistral key
make run

Python 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.

Your first agent

Talk to the agent over HTTP

The CLI is a client of the same runtime API. Keep the pod running in another terminal.

Interactive client
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.

Direct HTTP · local sample configuration
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.

Your first agent

Make the agent available to a team

The Python definition becomes a discoverable template; a team enrolls an instance.

01

Connect the pod

The operator configures the runtime catalog source and its browser-facing route.

02

Discover the template

The Control Plane reads the pod’s /agents/templates endpoint.
The catalog identifies the source runtime and agent definition.

03

Create an instance

An authorized user enrolls the template for a team and configures its settings.

04

Chat in Fred

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.

Part 3 / 6

Give your agent tools and a workflow

Connect business operations and control how the work gets done.

Tools and workflows

A Python function becomes an agent tool

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}
1. Define the tool

Typed arguments describe what the model can pass.

2. Give it to the agent

Instructions guide the model; tools lists what it can call.

3. Register the agent

The pod serves this registry through create_agent_app.

You write the function and instructions. Fred runs the tool-calling loop.

Tools and workflows

Call a service through MCP

MCP is a protocol for discovering tools and invoking them across a service boundary.

Your agent

Declares which MCP servers it needs.

→
Fred runtime

Connects to the configured servers and invokes tools.

→
MCP server

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.

Tools and workflows

Use a graph to define the workflow

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.

classifygreetanswerfinalizegreetingquestion

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.

Tools and workflows

Pause before committing an action

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.

Part 4 / 6

Build an application around your agent

Bring a dedicated interface, a business API and agent tools together.

Build an application

One business API, two ways to use it

A person uses your interface. An agent calls your MCP tools. Your service owns the records.

Your UIEmbedded iframe Fred host + proxyForwards user requests iframe SDKpostMessage Agent podConversation + tool calls Your MCP endpointTools exposed by your API MCP / HTTP Your APIBusiness rulesApplication-owned data HTTP User identity*

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.

Build an application

Connect your interface to Fred

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.

Build an application

Expose your business API as MCP tools

The current samples keep the interface, API and tools around the same service.

1. Select operations

Tag the API routes agents may call. Untagged routes remain available to the UI.

2. Mount and register

Expose /mcp and add its server ID to the runtime catalog.

3. Grant access

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-tracker

The API validates the caller and team access for both people and agents.

Build an application

Choose who owns the durable record

The two sample applications make different choices about writes and storage.

Document TriageProgress Tracker
User taskReview documents and record a decisionTrack tasks, notes and decisions
Agent roleRead the board and propose triageRead and update task records
Who writes?The person, through the applicationPeople and agent tools, through the API
StorageTeam workspace in Knowledge FlowApplication-owned SQLite database
Agent accessFred’s platform document toolsMCP 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.

Part 5 / 6

Connect your documents

Keep a library up to date and let agents retrieve the information they need.

Knowledge Flow

Knowledge Flow and Knowledge Bases

One service manages the documents; a connector keeps their source in sync.

Knowledge Flow

Receives documents, processes their content and indexes it for retrieval.

Manages the libraries and document lifecycle used by Fred.

A Knowledge Base pod

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.

Knowledge Flow

How documents become useful to an agent

Ingestion happens when content changes. Retrieval happens when a question needs it.

When a document is added or updated
Source

Upload or source synchronization

→
Knowledge Flow

Process content and build indexes

→
Team library

Documents available for retrieval

When the user asks a question
Agent search tool

Query with the current access context

→
Relevant passages

Content and source references

→
Model response

Use the retrieved evidence to answer

Retrieval supplies context to the model; it does not train the model on your documents.

Knowledge Flow

Publish a document through the SDK

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.

Knowledge Flow

Start with the local-folder sample

Understand the synchronization loop before connecting a remote source.

Try the source scan locally
cd ~/Fred/fred-samples/knowledge-bases/local-folder
make declaration
CONFIG_FILE=/nonexistent ENV_FILE=/nonexistent \
  make sync ROOT=/path/to/notes

Without 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.

What the handler owns

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.

Part 6 / 6

Develop close to production

fred-deployment-factory runs the whole platform on your machine, in two ways.

Local platform

Two local modes, two purposes

Both run the same infrastructure: Keycloak, PostgreSQL, OpenSearch, OpenFGA, Temporal and S3 storage.

Docker Composek3d
PurposeDebug one application fastDeploy as production does
InfrastructureContainers on your host: make docker-upA local Kubernetes cluster: make k3d-up
Your codeA process from your checkout: make runYour images and Helm chart: make k3d-app
Change loopEdit, restart, set a breakpointRebuild and roll out; rerun to converge
IdentitiesFixed local defaultsDeclared 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.

Local platform

Docker: the fast debug loop

The infrastructure runs in containers; Fred and your pods run as local processes.

Start the platform
# 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 four

First 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.

Why start here

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.

Local platform

k3d: the platform as production runs it

Every application is deployed with its own Helm chart, in a local Kubernetes cluster.

make k3d-up

The infrastructure, plus logs, events and metrics collection

→
make k3d-app DIR=../fred

Fred's chart with the production posture

→
make k3d-app DIR=<your repo>

Your application, next to Fred

What works on k3d has met the real chart, identities and permissions.

Local platform

Make your application deployable on k3d

Your repository carries its own deployment; the factory names no application.

your-repo/deploy/k3d/
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 sync

Only the helmfile is required. make k3d-app-validate lints and renders without touching the cluster.

identities.yaml
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.

Local platform

Find what went wrong

The k3d stack collects every pod's logs, the Kubernetes events, metrics and workflows.

From fred-deployment-factory
make k3d-health
bin/k3d-observe trace <id>
bin/k3d-observe logs '<query>'
bin/k3d-observe kpi

health: restarts and why, warnings, errors and HTTP 5xx per service. trace: every line naming a run, document or workflow.

In the browser

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.