Scalable Expert-based Task Topology
Current source release: 0.13.2 includes the v0.13 adapter capabilities,
passive health, normalized errors, explicit capability-based selection,
sanitized adapter tracing, and opt-in retry/circuit breaking. SETT describes
and filters adapters but never chooses a provider: applications construct,
name, and order every route themselves. The voice roster now includes
remote, local, and explicitly community/unofficial implementations, all
behind the existing TTSBase/STTBase boundaries. A dependency-free
sett.testing kit lets third-party adapters verify the same contract. This
patch also removes implicit stderr logging overhead and rejects unroutable
actions before governance, payload, or idempotency work begins. The local
voice roster now includes an optional Kyutai Pocket TTS adapter with lazy
model loading, voice conditioning, and complete PCM16 WAV output.
See docs/adapters.md, the canonical
adapter contract, and
CHANGELOG.md for details.
Version 0.12.0 added lifecycle management: cancellation, deadlines, structured outcomes and idempotency, entirely alongside the existing API. Its controlled entry points remain separate from the original synchronous API and feed the adapter lifecycle contract introduced in 0.13.0.
Before that, 0.11.0 introduced immutable, derivable ExecutionContext
objects and complete causal tracing across routing, agents, experts,
pipelines, governed memory publication, policy decisions, actions, handlers,
results, rejections, and errors. Traces are tamper-evident, exportable
through sanitized views, and never inspect private-memory values or record
application payloads by default. Its design is maintained in
docs/execution_context.md, and its upgrade notes
are in CHANGELOG.md.
Previous release, 0.10.1, hardened documentation and public-tree
consistency; 0.10.0 added a fourth, optional PhrasingExpert hook,
verify_facts(phrased, facts, context), for validating already-phrased text
against known facts and swapping it out if it contradicts them, motivated
by two independent downstream subclasses that each needed exactly this.
See CHANGELOG.md for the full entry.
SETT is a modular multi-agent AI framework built around domain-specialized expert agents coordinated by a central orchestrator.
Inspired by the Badger Architecture
(Rosa et al., 2019). SETT applies Badger's philosophy of coordinated expert
agents at a macro scale: pre-designed, domain-specialized agents working
under a single orchestrator, each maintaining independent memory,
communicating only final results through a shared universal memory layer,
with an ethical governance layer intercepting every action submitted as an
Action (via propose_action/submit_action) and every write to universal
memory, before either one takes effect.
Unlike frameworks that treat the language model as the system itself, SETT separates:
- Reasoning: pre-designed experts, one task each
- Communication: agents publish events, they never call each other directly
- Memory: private per agent, universal only for final results
- Execution: real-world side effects submitted through
SETTExecutorrun through a single, auditable gate - Ethical validation: a governance layer, not a prompt that can be skipped
This separation makes complex multi-agent systems easier to audit, extend, and secure: instead of one large, opaque agent loop.
SETT is not published on PyPI. Install it from source:
git clone https://github.com/EduDanielV/sett-framework.git
cd sett-framework
pip install -e .# With LLM support
pip install -e ".[anthropic]"# Claude
pip install -e ".[openai]"# GPT
pip install -e ".[gemini]"# Gemini
pip install -e ".[all]"# All adapters💡 Want a free, offline, local LLM instead?
OllamaAdapterneeds no extra install at all: just Ollama itself running on your machine. Seedocs/api_reference.md.
fromsettimportSETTOrchestrator, SETTAgent, SETTExpert, EthicalFilter, SETTExecutor# 1. Define an expertclassMyExpert(SETTExpert):
defresolve(self, context):
result= {"answer": f"Processed: {context.get('input')}"}
ifself._private_memory:
self._private_memory.write("last_input", context.get("input"))
returnresult# 2. Define an agent that submits a real-world side effect as dataclassMyAgent(SETTAgent):
def__init__(self):
super().__init__(name="MyAgent", domain="my_domain")
self.register_expert(MyExpert(name="my_expert"))
defprocess(self, input_data):
analysis=self.get_expert("my_expert").resolve(input_data)
self._publish_to_universal(analysis)
# Actions as Data: describe intent, don't perform it directly.# The Executor is the only thing that can call the real handler,# and only after the EthicalFilter approves it.result=self.submit_action("send_notification", payload={"msg": analysis["answer"]})
return {**analysis, **result}
# 3. Define the handler that performs the real side effectdefhandle_notification(payload):
print(f"Real-world side effect executed: {payload.get('msg')}")
return {"delivered": True}
# 4. Build and wire the systemorchestrator=SETTOrchestrator(ethical_filter=EthicalFilter())
executor=SETTExecutor()
executor.register_handler("send_notification", handle_notification)
orchestrator.register_executor(executor) # order-independentorchestrator.register_agent(MyAgent())
# 5. Run: fails closed if the EthicalFilter rejects the actionresult=orchestrator.process({"input": "hello"}, domain="my_domain")
print(result)
# Real-world side effect executed: Processed: hello# {'answer': 'Processed: hello', 'delivered': True}# 6. Every decision the EthicalFilter makes is logged: nothing happens# silently, whether it was allowed, warned, or rejected.forentryinorchestrator.get_ethical_audit_log():
print(f"[{entry['verdict'].upper()}] {entry['action']}: score: {entry['harm_score']:.2f}")
# [ALLOW] memory_write: score: 0.50# [ALLOW] send_notification: score: 1.50- ✔ Expert-based multi-agent architecture
- ✔ Independent private memory per agent
- ✔ Universal shared memory for final results only
- ✔ Actions as Data execution model
- ✔ Ethical governance layer intercepting submitted actions and memory writes
- ✔ Fail-closed execution: detached Executor, missing filter/handler, or rejection → nothing runs
- ✔ Defensive shared-memory and audit snapshots with verifiable hash chains
- ✔ Native pipelines: chain agents with explicit, hand-to-hand data flow
- ✔ Cooperative cancellation addressed by the same run_id your traces expose
- ✔ Monotonic deadlines that nest downward and never extend upward
- ✔ Structured outcomes that keep a rejection, a timeout and a failure apart
- ✔ Idempotency keys and opt-in retries at the real-world effect boundary
- ✔ Swappable LLM adapters (Claude, GPT, Gemini, Ollama)
| Concept | Description |
|---|---|
SETTOrchestrator | Brain of the system. Coordinates agents, manages universal memory. |
SETTAgent | Domain specialist composed of experts. Has its own private memory. |
SETTExpert | Atomic unit. Resolves one specific task. |
SETTExecutor | The one gate for real-world side effects submitted through it (submit_action()/submit()/submit_controlled()), executed only after ethical approval. Side effects performed directly in application code, outside SETTExecutor, are not intercepted. |
Action | A real-world side effect described as data, not code. |
UniversalMemory | Shared state. Agents publish only final results here. |
PrivateMemory | Each agent's internal workspace. Not exposed through the public API; isolated by convention, not by a runtime access-control boundary. |
EthicalFilter | Governance layer. Every action submitted through SETTExecutor passes through it before execution. |
ContextAnalyzer | Evaluates a proposed action in context; domain analyzers can return a SafetyAssessment separating urgency, action harm, and omission risk. |
run_pipeline() | Orchestrator method. Chains registered agents into an ordered sequence of stages with explicit, hand-to-hand data flow, never through universal memory, and fail-closed rejection handling. See docs/api_reference.md. |
1. Pre-designed experts: Experts know their domain before the system runs. They are not trained on the fly; they are built with purpose.
2. Independent memory per agent: Each agent has private memory invisible to the orchestrator and other agents. Only final results are shared.
3. Communication by events: Agents don't call each other directly. They publish to universal memory. The orchestrator synthesizes.
4. LLM as engine, not architecture: The language model is a tool inside an expert, not the system itself. Swap Claude for GPT or any local model by changing the adapter.
┌─────────────────────────────────────────────────────┐
│ SETTOrchestrator │
│ ┌───────────────────────────────────────────────┐ │
│ │ EthicalFilter (ring) │ │
│ └───────────────────────────────────────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │ Agent A │ │ Agent B │ │ Agent C │ │
│ │ Expert 1 │ │ Expert 1 │ │ Expert 1 │ │
│ │ Expert 2 │ │ Expert 2 │ │ Expert 2 │ │
│ │[private] │ │[private] │ │ [private] │ │
│ └────┬─────┘ └────┬─────┘ └────────┬──────────┘ │
│ │ │ │ │
│ ┌────▼─────────────▼─────────────────▼──────────┐ │
│ │ UniversalMemory │ │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Real-world side effects (submit_action) follow a separate, fail-closed path:
Agent ──Action──▶ EthicalFilter ──approved?──▶ SETTExecutor ──▶ real client
│
└──rejected──▶ nothing runs (fail closed)
A full reference implementation built on SETT is currently in development. It will be published here when ready and will demonstrate the framework in a real-world application covering health monitoring, empathic interaction, schedule management, and emergency response.
SETT is free and MIT-licensed for everyone, and stays that way. Sponsoring is a way to help fund maintenance time on the framework layer itself.
Nobody yet; you could be the first. See SPONSORS.md
for tiers.
This is an independent, solo project: issues, ideas, and pull requests
are welcome. See CONTRIBUTING.md.
MIT License
Copyright (c) 2026 Eduardo Daniel Viñales
Academic inspiration: BADGER: Learning to (Learn [Learning Algorithms] through Multi-Agent Communication), by Marek Rosa et al., GoodAI, 2019