Platform Architecture
How Ensemble is built.
A web workspace, an orchestrator, three engines, eight tool servers and a knowledge layer. All of it runs on one server inside your network, and every part can be inspected.
01 Layers
Six layers, one direction of travel.
A request enters at the top and moves down. Nothing lower in the stack can reach up and change the layer above it.
WorkspaceWhat people use, in the browser.
- Chat and documents side by side
- Spec pool with versions
- Kanban board
- Memory page
- Admin: agents, roles, environments
OrchestratorStarts, watches and stops every run.
- Roles and rulebooks
- Tool policy per user
- Memory block at start
- Run log and usage
- Cancel and resume
EnginesThe coding agent that does the reasoning.
- Claude Code
- Codex
- OpenCode
Tool serversNarrow, named actions. No general shell.
- db
- files
- precedent
- memory
- spec
- build
- test
- video
KnowledgeRebuilt every evening.
- Vector index
- Keyword index
- Reranker
- Relationship map
- Table cards
- Memory store
EnvironmentsWhere changes are tried.
- Isolated copy
- Development
- Test
- Staging
- Production · read-only
02 Rules
Every agent starts by reading its rulebook.
Rulebooks are short Markdown files, one per agent. They hold your team's conventions, not model trivia, and the orchestrator hands the same rulebook to every engine.
Written by your team.
Edit a rulebook and the next run uses it. No retraining, no redeploy.
Kept short on purpose.
Each agent reads one main file. Longer guides are opened only when the task needs them.
Backed by the platform.
Some rules are too important to leave to a prompt. Those are enforced in code: the Tester cannot install anything permanently, the database tool takes one checked SELECT, file tools stop at the workspace, and a sealed spec outranks memory.
# Builder You work from the sealed spec. Nothing else is a requirement. ## Before you write - Read the current source of every object you touch. - Read earlier change records for the same objects. - If the spec and the system disagree, stop and say so. ## While you write - Change only what the spec asks for. Never rewrite a whole file to change one block. - One change record per object. One line on why. - Update the process diagram only where your steps changed. - Do not invent limits. A value comes from the spec or from the system, never from you. ## Before you hand over - Run build.check_code until it is clean. - Pack with build.package. You cannot install it. The Tester does that, and removes it afterwards.
03 Tools
More than forty tools, each with one job.
Agents never get a general shell on your systems. They get named tools with narrow inputs, and each role sees only its own.
schemasobjectscolumnsconstraintsrowssourcesql
All three agents
Read-only
Goes through a separate reader service. One SELECT per call, checked before it reaches the database, ten-second limit, bounded rows. Table cards include row counts, keys and indexes.
readglobgrep
All three agents
Workspace only
Stops at the agent's workspace and the folders you allow. Read bans apply on every engine. Images and PDFs are turned into something the model can read.
search
Analyst, Builder
Read
Hybrid search over the nightly index: meaning, exact keywords and a reranker.
savegetfixdelete
Analyst, Builder
Own memory
The user is taken from the session, never from the model. The Tester has no memory tool.
readformsupdatewrite_requirementwrite_scenariowrite_open_pointimport_from_processremove_form
Analyst
Spec only
read_formtask_listread_codewrite_codefix_codecheck_codewrite_changeread_changefix_changedelete_changeupdate_graphfetch_current_sourcepackagetest_resultswrite_notedispute_review
Builder
Package only
Writes go into the change package, not into a live system.
read_formread_codepackageprepare_envisolated_usersinstall_packageseed_datastart_processdry_sqldry_pythonbrowser_testbrowser_testswrite_result
Tester
Isolated copy only
Everything the run installs or creates is removed when it ends.
framestrip
Analyst, Builder
This chat only
Lets an agent look at one frame, or a strip of frames across a few seconds, in a recording attached to the chat. It can zoom into one part of the screen.
04 Retrieval
Retrieval that knows the shape of your system.
Ensemble indexes units your team recognises: a process, a step, a data source, a procedure. Not anonymous text chunks.
One card per unit.
A model describes each unit once: what it does, the tables it reads and writes, the screens that call it. The card is regenerated only when the unit changes.
Three signals, then a reranker.
Dense embeddings find meaning, a keyword index catches exact names and codes, and a reranker orders the final list.
Relationships mined from code.
Where the schema has no foreign keys, joins found in source code and procedures become a relationship map the agents can read.
Cheap to keep fresh.
The nightly run compares fingerprints and skips what has not changed. An evening with no changes takes under two minutes and no model tokens.
Our internal evaluation, previous index struck through.
{
"query": "approval routed by amount",
"mode": "hybrid",
"results": [
{
"unit": "purchase-request / step 4",
"card": "Routes to manager or finance
director depending on amount.",
"tables": ["PURCHASE_REQ", "APPROVAL_LOG"],
"score": 0.91
},
{ "unit": "travel-advance / step 2", "score": 0.84 },
{ "unit": "petty-cash / step 3", "score": 0.79 }
]
}
05 Memory
How a memory is born, used and retired.
Memory is one small store per user, outside every engine. That is why it survives a change of engine, and why you can read every entry.
Captured
An agent notes a preference or a decision from the user's own words, with the message it came from.
Shown
A short notice appears with Undo. If nobody touches it, the entry stays.
Recalled
Preferences load at the start of a session. Decisions load when their process or data source is opened.
Distilled
Each evening the Archivist reviews the day, checks for near-duplicates and keeps what matters.
Retired
When an entry stops being true it is marked outdated, not deleted.
The same block for every engine.
The orchestrator builds one short memory block and gives it to every engine in the same way.
Personal by default.
Decisions tied to a process can be shared with the team if you switch that on. Preferences are always personal.
Past work needs no model.
Seals, handovers, test runs and releases are written to memory by the platform itself.
{
"type": "decision",
"text": "Thresholds compare in base currency.",
"linked_to": { "process": "expense-approval" },
"source_message": "msg_8f21",
"scope": "personal",
"written_by": "analyst",
"created": "2026-10-15",
"status": "active"
}
06 Engines
One stream, whichever engine runs.
Each engine reports its work in its own format. The orchestrator turns all three into one stream of messages, tool calls, results and usage, so the workspace never needs to know which engine ran.
Same tools everywhere.
Tool servers are attached to each engine with the same permissions. An agent cannot see a tool its role does not allow.
Versions you control.
Engine versions are installed side by side. A new version is tried against every model in use before it becomes the default, and switching back takes seconds.
Effort that means something.
Each project maps low, medium, high and max to real models. The browser agent follows the effort of the conversation it serves.
Stops when told.
Cancelling a run ends the engine and every tool process it started. A step limit stops a model that will not stop itself.
[agents] ; default engine per role analyst = claude-code builder = codex tester = codex [people] ; one person, one override alex = opencode [effort.core-system] low = fast-model medium = balanced-model high = strongest-model max = strongest-model
14:02:11 analyst db.sql read-only 0.41 s 6 rows 14:02:15 analyst spec.write_requirement R1 14:05:40 builder build.write_code +38 −6 14:06:02 builder build.package #128 14:09:18 tester test.browser_test S3 passed 14:10:05 tester cleanup 0 rows left 14:10:06 memory memory.save decision
07 Integrations
Your board. Your repository.
Ensemble fits the way your team already tracks and ships work. Use what is built in, or connect what you have.
Boards
Built-in kanban
Every spec and change sits on a board inside Ensemble. Nothing else to set up.
Jira
Keep your board where it is. Specs and status stay linked to the issue.
Trello
Cards follow the spec from first request to release.
Repositories
Local Git
Changes land as commits on a branch on your own server.
GitHub and GitLab
Branches are pushed and opened as pull or merge requests for review.
Self-hosted Git and your own tools
Any Git server works. Prefer files? Ensemble hands over the package and change records.
Writing to an external board or repository is switched on per project. Until then, Ensemble only reads.
08 Deployment
One server. Your network. Your rules.
Ensemble is installed, not rented. It runs as a handful of services on a Linux server you control.
Services
- Workspace and API
- Web app and API behind your reverse proxy.
- Worker
- Starts and supervises agent runs.
- Reader
- The only path to your database, read-only, on a local socket.
Storage
- Workspace data
- One small embedded database for chats, specs, runs and memory.
- Search
- A vector database for the nightly index.
- Models for search
- An embedding and reranking service, on a GPU you already have or one we help you set up.
Accounts
- People
- Sign in with your directory. No passwords stored.
- Agents
- Run as an unprivileged system user with no sudo.
- Database
- A separate read-only account used only by the reader.
Want to see the parts moving?
We'll walk your architects through a live run, from the first tool call to the cleanup.