Agent on Sentinel
This guide walks you through the smallest deployable Naylence fabric:
- a Client node (CLI / one-off process)
- a Sentinel (routing + admission/policy boundary)
- a tiny Hello agent that runs directly on the sentinel
Topology: Agent on sentinel
Goal: Send a “Hello, Naylence!” request from a client node and see an agent (reachable via the sentinel) handle it and reply.
Shape

Prerequisites
- You’ve completed a language quickstart:
- Git + a terminal
This guide assumes you already know how to set up a minimal TS or Python project from the quickstart. Here we focus on the three files that make the topology work.
Step 1 - Create a project
Create a new folder anywhere:
Example layout:
agent-on-sentinel/
agent.py
client.pyStep 2 - Install dependencies
Install the Naylence SDK and a runner for your language.
python3 -m venv .venv
source .venv/bin/activate
pip install naylence-agent-sdkStep 3 - Create and start the agent on the sentinel
The sentinel is a long-running process. It accepts downstream connections (agents) and routes envelopes.
# agent.py
import asyncio
from typing import Any
from naylence.agent import BaseAgent, configs
AGENT_ADDR = "hello@fame.fabric"
class EchoAgent(BaseAgent):
async def run_task(self, payload: Any, id: Any) -> Any:
return payload
if __name__ == "__main__":
asyncio.run(
EchoAgent().aserve(
AGENT_ADDR, root_config=configs.SENTINEL_CONFIG
)
)Run it:
python agent.pyBy default the sentinel listens on port 8000. Keep this terminal running.
Pre-baked configs: Both SDKs ship generic configs (SENTINEL_CONFIG, CLIENT_CONFIG) that bake in opinionated defaults and let you override essentials via environment variables. They don’t set everything, for example, the admission URL stays empty, so we set FAME_DIRECT_ADMISSION_URL in the next step to tell the client where to reach the sentinel.”
Step 4 - Create and run the client
The client is a short-lived process that attaches to the fabric and calls the agent by address.
# client.py
import asyncio
from naylence.fame.core import FameFabric
from naylence.agent import Agent, configs
AGENT_ADDR = "hello@fame.fabric"
async def main():
async with FameFabric.create(root_config=configs.CLIENT_CONFIG):
remote = Agent.remote(address=AGENT_ADDR)
result = await remote.run_task("Hello, Naylence!")
print(result)
if __name__ == "__main__":
asyncio.run(main())Run it:
source .venv/bin/activate
export FAME_DIRECT_ADMISSION_URL="ws://localhost:8000/fame/v1/attach/ws/downstream"
python client.pyExpected outcome:
- Client prints the result (an echoed payload).
- Sentinel logs routing activity.
- Agent logs that it handled the request.
Optional steps
- See the raw envelopes flowing between the client and the sentinel-hosted agent by setting
FAME_SHOW_ENVELOPES=truebefore running either process. - Mix runtimes: run the TS agent with the Python client or vice versa, the protocol is compatible.
- Turn on verbose debugging with
FAME_LOG_LEVEL=debugto watch what the fabric is doing behind the scenes.
You might be wondering what the FAME_ prefix stands for. It’s short for Federated Agentic Messaging Engine - the core messaging/runtime layer in Naylence. We often just call it “the runtime”, but environment variables keep the historical FAME_ prefix.
Common issues
- Wrong admission URL: agent/client can’t connect or silently hang. Double-check the exact
ws://.../attach/ws/downstreampath. - Port already in use: something else is bound to
8000. - Duplicate identity (especially when you copy/paste configs across multiple terminals or tabs): one instance can “steal” the route.
Next step
Once this works, the next upgrade is to move agents off the sentinel boundary (or add multiple agent nodes) without changing how the client calls them: