Seen, checked, on record.
A multi-agent workplace: humans and citrus-named AI coworkers in one group chat, doing work with real consequences.
▶ Watch the 60-second demo · mock data · try it locally with npm run dev:mock
Most multi-agent demos stop at talking. Yuzu's coworkers act — and every action is seen, checked and kept on record. A Slack-like group chat holds humans and up to eight AI coworkers (Yuzu the PM, Lime the researcher, Kumquat the engineer, Pomelo the customer liaison, …). Every agent shares one internal architecture — chat triage, safety review, planning and cognition, a single-threaded main consciousness, subconscious supervision, habit and deep memory, behavior review and tool calling — but has its own role, permissions, workspace and memory. They email clients, place trades and write code, behind two independent safety layers and a full trace of every module event.
The film and the screenshots run on the mock backend (
npm run dev:mock): the backend is simulated in the browser and every email and trade is fake and markedSIMULATED.
| Industry pain | Yuzu's answer |
|---|---|
| 🗣️ Eight agents, one chat, eight answers — agents talk over each other and ping-pong forever | Every coworker has a secretary module that triages the chat: IGNORE / REPLY / FORWARD. Mention Lime and only Lime wakes up; loop guards (closure flag, causal depth, pair limiter, @all budget) end every thread. |
| 🛡️ One poisoned email hijacks the agent — prompt injection, credential leaks, overspending | Everything going in or out is checked twice: an AI safety review (GATE inbound, MASK tool results) and permissions written in code (PermissionGuard, per-agent limits, ApprovalGate). A spoofed acme-c0rp.co invoice is blocked at the door; a $90,600 trade over a $25,000 limit never leaves. |
| 🔍 Nobody can see what the agents did | Every module reports START / STATE / END / ERROR spans to the MonitorBus: a live event stream, a trace waterfall per action, the exact model request/response of every call, and an incident log. |
| 💸 One big model everywhere | The main mind thinks in plain language; lighter models do the structured dirty work. Three tiers (IMPORTANT / DEFAULT / LIGHT) map to models in the console, and a cache-friendly prompt layout keeps most prompt tokens on the cache. |
| 🙋 Humans lose control of decisions that matter | Agents ask with question and approval cards right in the chat; anything above an agent's limits waits for a human click, and finished task lists need a human to approve them. |
Left the group chat with @mentions, security notices, question and approval cards. Middle the office floor: each citrus coworker at its desk, with a live bubble showing the active module and what it is doing. Right the insights: tickets and task lists, token usage, the simulated world and the full trace.
A human request without an @mention reaches the PM only; a mention wakes exactly the coworker it names. The triage verdict
itself is observable: the desk bubble switches to CHAT · Triage … REPLY while the others keep working.
![]() |
![]() |
Every block is on record, tagged with the layer that caught it: INBOUND · BLOCKED (the AI review masked a look-alike
domain asking to "ignore previous instructions"), GUARD · DENIED (code refused a notional above the agent's limit). Three
trades, three outcomes: executed within limits, rejected by a human, blocked by the system before a human ever saw it.
![]() |
![]() |
Click any event and get the whole chain: chat triage → safety review → planning → main consciousness → tool calls, each span with its module, timing and the raw model call. Usage is split by agent, module, tier and model, with the cache hit rate the provider reports.
flowchart TB
msg([Group message]) --> chat[chat: ChatService · RoomWindow · fan-out]
chat --> pre[ChatPrefilter: code, @mention routing]
pre --> triage[external.chat: IGNORE / REPLY / FORWARD]
triage --> intake[internal.intake]
intake --> safety[external.safety: GATE / MASK]
safety -- unsafe --> notice[[Yellow security notice]]
safety -- safe --> plan[internal.planning ∥ internal.cognition: habits]
plan --> pool[(Pool: EXTERNAL · SELF · SUBCONSCIOUS · REVIEW)]
pool --> main[internal.consciousness: single-threaded Main · ACT / THINK / END]
main --> act[external.toolcall: ActionPipeline]
act --> behavior[external.behavior: review every action]
behavior --> guard[tool: schema → PermissionGuard → ApprovalGate → run]
guard --> world[web · email · trade · code · files · tickets]
world --> intake
main <-.-> sub[internal.subconscious: advice · learn · remember]
sub --> mem[internal.memory: habit + deep memory]
card[card: question / approval cards] --> intake
subgraph observability
monitor[monitor: MonitorBus · desk state] --> realtime[realtime: SSE hub]
end
triage & safety & plan & main & act & guard & sub --> monitor
Each package has its own README.md; the design is in docs/ARCHITECTURE.md, the REST/SSE
contract in docs/API.md.
Agent anatomy
| Group | Module | Tier | Responsibility |
|---|---|---|---|
| External (AI) | Chat | DEFAULT | Decide whether a group message matters: IGNORE / REPLY / FORWARD (+ ack) |
| External (AI) | Safety review | DEFAULT | GATE inbound content; MASK unsafe parts of tool results |
| External (AI) | Behavior review | DEFAULT | Check every action Main decides; any violation rejects the whole batch |
| External (AI) | Tool calling | DEFAULT | Decompose natural-language actions into tool calls and dispatch them |
| External (AI) | Monitor | LIGHT | Summarize what the agent is doing for the desk bubble |
| Internal (AI) | Main consciousness | IMPORTANT | Single-threaded; ACT / THINK / END over the whole pool |
| Internal (AI) | Planning | DEFAULT | Maintain the task list |
| Internal (AI) | Cognition | LIGHT | Pick the habits that apply to new input |
| Internal (AI) | Subconscious | DEFAULT | Supervise Main; send first-person advice; propose things to learn/remember |
| Internal (AI) | Learning / Memory | DEFAULT | Save and modify habit and deep memory (dedup, conflicts) |
| Tools (AI + code) | Web, Email, Trade, Code, File, Memory-read, Chat, Ask-user, Tickets, Learn | DEFAULT | Execute with code-level permission guards |
Packages (ai.yuzu.*)
| Package | Responsibility |
|---|---|
agent |
Agents as employees: identity, job, persona, permissions and limits |
bootstrap |
GET /api/bootstrap: the full room snapshot the UI renders before opening the stream |
card |
Question and approval cards: an agent asks, a human answers over REST, never through chat |
chat |
The group chat: one write path, an in-memory window, mentions and agent fan-out |
common |
Dependency-free building blocks shared by every feature package |
config |
Typed configuration and core infrastructure beans |
demo |
One-click setup of the collaboration demo: four role-matched coworkers and their simulated world |
external |
The agent's external modules (all AI): chat triage, safety review, behavior review, tool calling |
internal |
The agent's internal modules (all AI): consciousness, subconscious, planning/cognition, memory, learning |
llm |
Model access layer (OpenAI-compatible Chat Completions): tiers, structured output, usage metering |
module |
The base classes every AI module is built on |
monitor |
Every module reports here; keeps each agent's live desk state |
persistence |
Shared persistence building blocks (MySQL via Spring JDBC) |
realtime |
Server-Sent Events hub: every live update the frontend sees flows through here |
room |
Rooms, human membership and the room directory |
settings |
The console's model settings and encrypted API keys |
sim |
The simulated world: fake e-mail and fake trading, clearly marked SIMULATED in the UI |
task |
Tickets and every agent's one current task list |
tool |
Tools, "half AI, half code": the AI decides arguments, code executes with its own guards |
trace |
Read side of the monitor history stored in module_event |
web |
The only door to the outside web: search, fetch, extract, guard and snapshot |
workspace |
Per-agent workspaces an agent can never step outside of |
- JDK 21+, Maven 3.9+, Node 20+.
- MySQL 9 on
127.0.0.1:3307— either the MySQL binaries (mysqld,mysql) on the PATH, or Docker. - An OpenAI-compatible endpoint (OpenAI, the EdgeOne Makers gateway, …), configured in the Console. Not needed for the mock mode.
cd frontend && npm install && npm run dev:mock # http://localhost:5173, backend simulated in the browser./scripts/db.sh init-db # with mysqld: private instance on 127.0.0.1:3307 (data in data/mysql)
docker compose up -d db # without mysqld: the same instance in a container, same port and flags
./scripts/dev.sh # starts the database, the backend (:8080) and the frontend (:5173)
curl -X POST "http://localhost:8080/api/demo/seed?roomId=room-0001" # hire the four demo coworkersThe frontend must stay on port 5173 — it is the only origin the backend's CORS policy accepts. Either way the database is
Yuzu's own, never a system MySQL installation, and both paths set the server flags the code depends on
(innodb_ft_enable_stopword=OFF for ngram recall, UTC, utf8mb4). Backend tests use the yuzu_test database on the same
instance; mvn -f backend test needs it running.
Yuzu targets a POSIX file system. On Windows everything runs, but the workspace cannot detect hard links (logged once at WARN) and the code sandbox is unavailable, so those tests report as skipped.
Six numbered chips under the top bar jump the workspace to the state that shows off one pillar of the design (triage,
model tiering, subconscious, safety, memory, business). Keys 1–6 select a step, Esc leaves. The tour only changes
what is on screen: it never posts a message or touches the simulated world. A ten-minute walkthrough of the live stack is in
docs/DEMO.md.
Demo film (mock data)
The 60-second film lives in videos/yuzu-launch/ as a HyperFrames
project (HTML + GSAP rendered to video):
- Footage:
node videos/yuzu-launch/scripts/record.mjsrecords the clips and 2× stills from the mock-mode frontend with Playwright (PLAYWRIGHT_PKGpoints at a directory withplaywrightinstalled). - Story:
STORYBOARD.mdand the locked narration inSCRIPT.md; one composition per frame incompositions/frames/. - Audio, fully offline: Kokoro TTS (
am_michael) narration with burned-in captions; an ACE-Step 1.5 music bed (scripts/gen_music.py, arranged on the 104 BPM bar grid byscripts/arrange.py); procedural SFX (scripts/sfx.py). - Build:
cd videos/yuzu-launch && bash scripts/rebuild.sh(Git Bash on Windows) reassembles from.hyperframes/frames-src/, renders and normalizes to −14 LUFS →renders/yuzu-demo.mp4. README images and the preview:node docs/img/src/render.mjs(samePLAYWRIGHT_PKG).
Endpoint overview
| Group | Endpoints |
|---|---|
| Session | POST /api/session/join, GET /api/bootstrap?roomId= |
| Chat and cards | /api/rooms/{roomId}/messages (list, post), POST /api/cards/{cardId}/answer |
| Agents | GET /api/roles, /api/rooms/{roomId}/agents (list, hire), PATCH/DELETE /api/agents/{agentId}, pause / resume / interrupt, room stop-all / resume-all, working-memory, tasks, events |
| Tickets and approvals | GET /api/rooms/{roomId}/tickets, POST /api/task-lists/{listId}/approve |
| Settings (console) | /api/settings/llm (get, put), key, test, models |
| Usage and trace | GET /api/usage, GET /api/traces/{traceId}, llm-calls, GET /api/llm-calls/{callId}/payload |
| Simulation and demo | GET /api/sim/emails, trades, portfolios, POST /api/demo/seed?roomId= |
| Realtime | GET /api/stream — Server-Sent Events for every live update |
Full contract: docs/API.md.
- Everything inbound is reviewed: human messages, fetched web pages, received emails and tool results pass the AI safety review (GATE / MASK) before any internal module sees them; a blocked item becomes a public security notice in chat.
- Everything outbound is reviewed twice: behavior review of every action Main decides, a second review for high-risk tools, then code — schema check → PermissionGuard (role permissions, per-agent limits such as allowed email domains and trade notional) → ApprovalGate (a human card above the auto-approve limit) → the guard again inside the tool.
- Unforgeable sources: pool messages carry a code-assigned origin (
EXTERNAL / SELF / SUBCONSCIOUS / REVIEW); external input is always attributed in the first person ("Alice told me…"). - Containment: per-agent workspaces with path confinement; the web module is the only door to the internet; API keys are stored encrypted and only a mask is returned.
- Humans can stop anything: pause, interrupt or stop the whole room; every stop is recorded as a
CANCELLEDspan.
- Version starts at
0.0.0(seeVERSION): patch bump per step, minor bump per milestone. - Every class/function carries a one-line comment
v<version> 🍊 <what it does>. - Every package/feature folder has a
README.mddescribing its responsibility. - All code, comments, UI text and prompts are in English —
EnglishSourceGuardTestfails the build on a CJK character anywhere underbackend/src/main,frontend/srcorscripts(test fixtures are exempt: there the characters are data).
Yuzu was built in one day, on 2026-09-19, at The Executable World full-stack AI hackathon (FIG Studio × Tencent EdgeOne × AgentX, San Francisco), where it took 1st place in Track 2, "Production-Ready AI Agent"; it has been hardened since (Windows/Docker portability, CJK habit recall, the English-only source guard, this redesign).
Third-party components: Spring Boot, Flyway, Caffeine, MySQL Connector/J, networknt json-schema-validator, jsoup, JTokkit; frontend: React, Vite, Tailwind CSS, zustand, motion, react-virtuoso, @fontsource (Bricolage Grotesque, Plus Jakarta Sans, Geist Mono). Demo film: HyperFrames, GSAP, Kokoro TTS, ACE-Step 1.5, Playwright, ffmpeg.





