1114ee5ea0 [77719d3f] A2A team telemetry: coordination event notifications for 5 event types (#477)
* [13d03d5c] Add 5 coordination-event notification producers + wire at chokepoints (#472) (#474)

* [13d03d5c] Add 5 coordination-event notification producer methods

* [13d03d5c] Wire reassignment/collision/unblock/dependency-revival notifications

* [13d03d5c] Wire stale-claim-reaped notification into orchestrator reaper

* [13d03d5c] fix(runtime): guard reaper's UUID annotation + defensive attr access

The stale-claim-reaped notification hook added a runtime-unquoted
`UUID` type annotation (only imported under TYPE_CHECKING, so the
module raised NameError on import) and a direct `t.assigned_to`
attribute access that crashes against the minimal test doubles the
existing reaper test suite uses. Quote the annotation and switch to
getattr-defensive access, matching `_assignee_is_provider_parked`'s
existing convention in the same file.

* [13d03d5c] test(notification): unit coverage for 5 coordination-event producers

One test per new send_* method (reassignment, collision-sequencing,
unblock, dependency-revival, stale-claim-reaped) following the
existing _FakeDb/_patch_db_context pattern, asserting subject/body/
related_task_id/priority/recipient-count, plus a no-recipients no-op
case for reassignment.

* [13d03d5c] test(task): prove reassign + unblock don't double-fire notifications

Two chokepoint-level tests mocking NotificationService at its defining
module: a repeated reassign() to the same already-current target skips
the notification (guarded by comparing against the pre-mutation
assignee), and a repeated unblock() on the same task only notifies
once since the second call short-circuits on the status!=BLOCKED
guard.

* [13d03d5c] style(task): ruff format the collision-sequencing wiring block

No behavior change — reflows the newly-added _notify_collision_sequencing
call site to satisfy ruff format's line-length rules.

* [13d03d5c] docs(backend): add coordination-event notification producers guide

Documented the 5 new NotificationService producers (reassignment, collision-sequencing,
unblock, dependency-revival, stale-claim-reaped) with fire conditions, double-fire
prevention mechanisms, and implementation patterns. Updated backend README to link the
new services guide for developers integrating new coordination events.

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>

* [3ee8150b] Frontend: render coordination-event notifications + e2e smoke coverage (#475)

* [69777c3a] test(e2e-smoke): add coverage for soft-block + unblock coordination notifications (#471)

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>

* [8eb82639] Render 5 coordination-event notification types with task deep-links (#470)

* [8eb82639] feat(notifications): add APPROVAL type icon and deep-link component test

Add missing APPROVAL member to the frontend NotificationType enum to
match backend roboco/models/base.py, wire its icon into the existing
typeIcons Record in the notifications page, and add a component test
covering type rendering and the task deep-link.

* [8eb82639] docs(notifications): document 5 coordination-event types and APPROVAL enum addition

Added comprehensive reference guide explaining the 5 notification types
(TASK_ASSIGNMENT, BLOCKER_ESCALATION, REVIEW_REQUEST, DOCUMENTATION_REQUEST,
APPROVAL), their visual identities (icon + color), use cases, and
deep-linking behavior to related tasks. Updated panel README with quick
reference table. TypeScript Record pattern ensures exhaustive type coverage
at build time.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [a27de2a8] fix(docs): reflow hard-wrapped notification-types.md to pass markdown gate (#479) (#481)

The Python quality gate on assembled PR #477 was red because the newly
added docs/frontend/components/notification-types.md (introduced by the
frontend coordination-event rendering commit) had manually wrapped prose
paragraphs, which scripts/reflow_md.py --check rejects as part of make
quality. Reflowed the file with scripts/reflow_md.py --apply (whitespace
only, no content change) so the check passes. ruff format/check, mypy,
xenon, vulture, bandit, and the full pytest suite (10284 passed) all
confirmed green on this commit; notification.py, task.py, and
orchestrator.py are untouched.

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

* [705419d5] Remove duplicate unblock notification and fix its dependent tests (#485) (#488)

* [705419d5] fix(notifications): remove duplicate unblock notification, fix its tests

The /unblock route was still calling delivery.notify_assignee_of_unblock()
(TASK_ASSIGNMENT) after TaskService.unblock() already sent the
send_unblock_notification() ALERT wired in by an earlier task — a real
duplicate notification on every unblock. Delete the route-layer call and
the now-dead NotificationDeliveryService.notify_assignee_of_unblock
method, fix the integration test that mocked it, and fix/extend the e2e
notification-coordination-events test to assert the persisted ALERT rows
(exact subjects) for both the direct-unblock and dependency-revival
producers instead of the old TASK_ASSIGNMENT assertion.

* [705419d5] docs(backend): update coordination-events doc for unblock duplicate removal

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>

* [6c142a73] docs(changelog): document restored coordination-event notification producers and add collision-sequencing double-fire test (#489) (#490)

Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech>

* [77719d3f] Seed system agent in e2e harness to fix unblock/dependency-revival notifications

The e2e harness's seed_company omitted the system sentinel agent that
production seeds via initial_data.py. The unblock and dependency-revival
notification producers default to from_agent="system", which
_resolve_agent_uuid looks up by slug in the DB. With no system row the
resolver returns None and _create_notification silently skips the
notification, so the two ALERT assertions got 0 rows instead of 1.

The soft-block test passed because it uses NotificationDeliveryService
which creates the notification directly with a real agent UUID as
from_agent, bypassing the slug resolution path entirely.

* [77719d3f] Use foundation UUID for system agent to avoid slug collision

The first attempt seeded the system agent with a random UUID. Other
tests (_seed_system_and_secretary, _seed_video_agents) check by the
fixed foundation UUID via session.get(AgentTable, uuid); not finding
it they INSERT their own system row, hitting ix_agents_slug. Using the
foundation UUID makes their check find the seed_company row and skip.

* [77719d3f] Fix dependency-revival notification event loop mismatch

The dependency-revival test calls _unblock_dependents directly via
stack.run_db, which creates a new asyncio event loop. Inside,
_notify_dependency_revival -> NotificationService._create_notification
opened its own session via get_db_context(), which reuses the singleton
_DbHolder engine — bound to the FastAPI server's event loop. The
asyncpg connection raised 'Future attached to a different loop' and the
exception was silently caught + logged as a warning, so the notification
never persisted and the test saw 0 rows.

Fix: add an optional db_session parameter to _create_notification and
the two send methods. When provided, use the caller's session directly
and skip the internal commit (the caller owns the transaction). The
TaskService's _notify_unblock and _notify_dependency_revival now pass
self.session, keeping the notification in the same event loop + session
as the task transition.

* [77719d3f] Scope system-agent seeding to notification tests only

Seeding the system sentinel in seed_company (commits 3bba7b32/617b7890)
fixed the 0-notification bug but caused 3 i_documented gateway_timeout
failures: every e2e test now paid notification-creation latency for
system-origin notifications that were previously silently skipped,
pushing the already-slow i_documented verb past its 120s timeout.

Move system-agent seeding out of seed_company and into a scoped
_seed_system_agent helper called only by the two coordination-event
tests that exercise send_unblock_notification /
send_dependency_revival_notification (both resolve from_agent='system'
via DB lookup). dev_lifecycle and state_machine tests revert to the
pre-fix behavior (system-origin notifications silently skipped, no extra
latency).

The event-loop fix (commit 7b95d77d: pass db_session=self.session to
_create_notification) is unchanged — dependency_revival still needs it
because stack.run_db creates a new event loop while _DbHolder.engine is
bound to the FastAPI server loop.

* [77719d3f] Fix reassignment notification deadlock + suppressed-notification commit regression

Two fixes in notification.py / task.py:

1. Cross-session self-deadlock in send_reassignment_notification:
   TaskService.reassign() flushes an uncommitted row lock on the task,
   then calls _notify_reassignment -> send_reassignment_notification ->
   _create_notification(db_session=None) which opens a SEPARATE session
   via get_db_context() and INSERTs a notification with related_task_id
   FK -> tasks.id. The FK key-share lock blocks on the request session's
   uncommitted exclusive lock, but the request can't commit until the
   notify returns -> 120s verb hard-cut. Fix: pass db_session=self.session
   so the notification joins the verb's own transaction, same pattern as
   the unblock/dependency-revival fix in 7b95d77d.

2. Suppressed-notification commit regression: the 7b95d77d refactor moved
   await db.commit() out of _create_notification_with_session into
   _create_notification's db_session=None branch, where it ran
   unconditionally — even when _create_notification_with_session returned
   early (suppressed: unresolvable from_agent / no recipients /
   refire-guard / dedup-hit). Fix: _create_notification_with_session now
   returns bool (False at each early return, True after delivery);
   _create_notification commits only when created is True.

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-13 06:38:15 +02:00
2026-06-07 02:53:51 +02:00
2026-07-11 09:45:54 +02:00
2026-05-05 03:19:43 +02:00

RoboCo

AI Agents Company - A virtual organization of 25 AI agents + 1 human CEO, designed to operate as a complete software development workforce.

Watch the 26-minute RoboCo intro on YouTube — what it is, a walkthrough, and how to use it
Watch the 26-min intro
what it is, a walkthrough, and how to use it
Watch the 2.5-hour Working with RoboCo build session on YouTube — taking a conversation all the way to a shipped feature
Watch the 2.5-hour build session
a conversation → a shipped feature

Twelve-second looping preview of the RoboCo control panel — the org tree, a task in progress, and an approval queue.
Watch the full 2:33 walkthrough (.mp4) →

Warning

RoboCo is early-stage, work-in-progress software (v0). It's under active development, runs in a homelab, and will have rough edges, breaking changes, and bugs. It is not production-ready and the API/database schema are not stable yet. Treat it as a working prototype to explore and build on — please don't expose it to the public internet as-is. Issues and PRs very welcome.

Tip

📚 Full documentation: docs.roboco.tech — install & first run, the company model, a page-by-page panel reference, model providers, the optional subsystems, deployment, and the API.

Overview

RoboCo implements a structured organizational hierarchy with formal communication protocols, task management, and quality controls. The system enables a single human (CEO) to orchestrate complex multi-project development at scale.

CEO (You, the human)
    │
    ├── Intake (on-demand interviewer: chats only with you to draft a task)
    ├── Secretary (on-demand chief-of-staff: reads company state, runs gated directives)
    ├── PR Reviewer (read-only main reviewer: inbound external/fork + internal PRs, and the root→master in-path gate)
    │
    └── Board (3 agents)
         ├── Product Owner
         ├── Head of Marketing
         └── Auditor (silent observer, reports to you)
              │
              └── Main PM (coordinates all cells)
                   │
                   ├── Backend Cell (6 agents: 2 Devs, 1 QA, 1 PM, 1 Documenter, 1 PR Reviewer)
                   ├── Frontend Cell (6 agents: 2 Devs, 1 QA, 1 PM, 1 Documenter, 1 PR Reviewer)
                   └── UX/UI Cell (6 agents: 2 Devs, 1 QA, 1 PM, 1 Documenter, 1 PR Reviewer)

The 25 agents = Intake + Secretary + PR Reviewer + the Board (3) + Main PM + the three 6-agent cells (18). Agents run on Anthropic Claude by default, or on xAI Grok (the official grok CLI on a SuperGrok subscription) — see the provider note under Configuration.

How it works

You hand a task to the company; it runs through a real build → review → document → merge pipeline and comes back to you to approve.

One full loop, put simply:

  1. You give the Board a task — they review it. The Product Owner and Head of Marketing turn your ask into requirements and acceptance criteria.
  2. You approve — the Main PM starts the work. A notification asks for your Approve & Start decision; approve, and the Main PM breaks it into per-cell subtasks.
  3. Each cell's PM delegates, supports, and triages its developers (UX/UI, Frontend, Backend).
  4. Developers build it, QA verifies and gates it, Documenters keep the books.
  5. Cell PMs merge their PRs into the Main PM's branch.
  6. The Main PM opens the final PR and notifies you "It's done!" — you approve and merge, or send it back for rework. (Only you ever merge to master.)

— Full circle —

See the full walkthrough, with screenshots →

Or watch the full panel walkthrough (video) →

Project Structure

roboco/
├── roboco/                      # Main Python package
│   ├── api/                     # FastAPI routes & schemas
│   │   ├── routes/              # API endpoints (tasks, git, agents, etc.)
│   │   └── schemas/             # Pydantic request/response models
│   ├── services/                # Business logic services
│   │   ├── task.py              # Task lifecycle management
│   │   ├── workspace.py         # Multi-agent workspace management
│   │   ├── messaging.py         # Agent communication
│   │   └── optimal.py           # RAG/Knowledge base (in-house pgvector)
│   ├── models/                  # Pydantic domain models
│   ├── db/                      # SQLAlchemy ORM & session
│   ├── enforcement/             # Task lifecycle state machine
│   ├── runtime/                 # Orchestrator for agent spawning
│   ├── agents/                  # Agent base classes
│   ├── mcp/                     # MCP server implementations
│   └── config.py                # Application configuration
├── agents/
│   └── prompts/                 # Agent system prompts (roles, teams, identities)
├── docs/
│   ├── rag/                     # Agent knowledge base (indexed into RAG)
│   └── map/                     # Exhaustive codebase map (agent-facing)
├── alembic/                     # Database migrations
├── CLAUDE.md                    # Claude Code guidance
├── docker-compose.yml           # Full stack, built from source
└── docker-compose.registry.yml  # Full stack, pulled from the image registry

Running RoboCo

You need Docker + Docker Compose and a Claude Code auth directory on the host (~/.claude, mounted into the orchestrator so agents can reach the model). Copy .env.example to .env and set at least ROBOCO_ENCRYPTION_KEY and ROBOCO_AGENT_AUTH_SECRET (that file shows how to generate each). However you start it, the whole company is reachable at one origin: http://localhost:3000.

Optional — run agents on xAI Grok instead of Claude. RoboCo can spawn agents on xAI's official grok CLI authenticated by a SuperGrok subscription (no metered API key). Run grok login once on the host and point ROBOCO_HOST_GROK_DIR at the resulting ~/.grok so it mounts into Grok agents; the orchestrator keeps the ~6h token refreshed for you. See the Grok block in .env.example (ROBOCO_HOST_GROK_DIR, ROBOCO_GROK_AGENT_IMAGE, ROBOCO_GROK_CLI_MODEL, ROBOCO_GROK_REASONING_EFFORT).

Option 1 — Run the pre-built images (quickest)

Every release publishes all RoboCo images to both the GitHub Container Registry and Docker Hub, so you can run the full stack without building anything. Use the registry compose:

git clone https://github.com/rennf93/roboco.git && cd roboco
cp .env.example .env                                   # then edit in your secrets
docker compose -f docker-compose.registry.yml pull
docker compose -f docker-compose.registry.yml up -d

Choose the registry and version with two env vars (defaults shown):

ROBOCO_REGISTRY=ghcr.io/rennf93   # or docker.io/renzof93
ROBOCO_VERSION=latest             # or a pinned release, e.g. 0.15.0

The orchestrator spawns the matching pre-built agent images on demand — no build toolchain or source compile on your host.

Option 2 — Build from source

The same full stack, built locally from the Dockerfiles instead of pulled:

git clone https://github.com/rennf93/roboco.git && cd roboco
cp .env.example .env              # then edit in your secrets
docker compose up -d              # builds images on first run, then starts everything

Option 3 — Local development (no full stack)

For hacking on the code itself, run only the backing services in Docker and the API on your host. RoboCo's own code requires Python 3.13+ (uv will fetch it if needed):

uv sync
docker compose up -d postgres redis ollama   # backing services only
uv run alembic upgrade head                   # migrate the database
uv run python -m roboco.cli                   # API + orchestrator

# Or just the API without the orchestrator:
uv run uvicorn roboco.api.app:app --reload --host 0.0.0.0 --port 8000

Configuration

Key environment variables (see roboco/config.py for all options):

# API Server
ROBOCO_HOST=0.0.0.0
ROBOCO_PORT=8000

# Database
ROBOCO_DATABASE_HOST=localhost
ROBOCO_DATABASE_PORT=5432
ROBOCO_DATABASE_NAME=roboco

# Workspaces (Multi-Agent Git)
ROBOCO_WORKSPACES_ROOT=/data/workspaces
ROBOCO_WORKSPACE_AUTO_CLONE=true

# RAG/LLM
ROBOCO_LOCAL_LLM_BASE_URL=http://roboco-ollama:11434/v1
ROBOCO_LOCAL_LLM_MODEL=glm-5.2:cloud

# Feature flags (default-off unless noted; toggle from Settings → Feature Flags)
ROBOCO_CONVENTIONS_ENABLED=false        # per-project architectural conventions standard
ROBOCO_TOOLCHAIN_MATCH_ENABLED=false    # build each target project under its own Python
ROBOCO_OVERLOAD_BREAK_ENABLED=true      # park a provider on a persistent model-API overload

Multi-Agent Workspace Structure

Each agent gets their own git clone for parallel development:

{ROBOCO_WORKSPACES_ROOT}/
└── {project-slug}/
    └── {team}/
        └── {agent-slug}/
            └── [git repository]

Example:
/data/workspaces/roboco/backend/be-dev-1/
/data/workspaces/roboco/backend/be-dev-2/

Task Lifecycle

backlog → pending → claimed → in_progress → verifying → awaiting_qa
    ↓                              ↓              ↓           ↓
cancelled                      blocked      needs_revision   awaiting_documentation
                               paused                              ↓
                                                           awaiting_pm_review
                                                                   ↓
                                                           awaiting_ceo_approval
                                                                   ↓
                                                              completed

Assembled, PR-bearing tasks pass through one extra stage — the in-path PR-review gate — before the PM merges:

in_progress → awaiting_pr_review → awaiting_pm_review
   (submit_up /      (pr_pass)
    submit_root)     (pr_fail → needs_revision)

The cell PM's submit_up (cell→root PR) and the Main PM's submit_root (root→master PR) open the assembled PR and enter the gate; a PR reviewer pr_passes it on to the PM merge or pr_fails it back. Leaf dev tasks (reviewed by QA) and branchless coordination roots skip the gate.

API Endpoints

Domain routes are mounted under /api:

Route Group Description
/api/tasks Task CRUD, lifecycle, claiming
/api/agents Agent management
/api/git Git operations (status, commit, push, PR)
/api/sessions Communication sessions
/api/messages Agent messages
/api/projects Project (repo) management
/api/work-sessions Git work session tracking
/api/optimal RAG/Knowledge base queries
/api/journals Agent journals/reflections
/api/orchestrator/status Orchestrator / dispatcher status

The agent gateway verbs are served separately under /api/v1/flow/{role}/{verb} (intent verbs) and /api/v1/do (content tools) — see the Agent Gateway.

Development

# Install dev dependencies
uv sync --all-extras

# Run tests
uv run pytest

# Format and lint
uv run ruff format .
uv run ruff check .
uv run mypy roboco/

# Type checking
uv run mypy roboco/

Core Principles

  1. Everything is a task - All work is tracked and documented
  2. No work without a task - Create task record first
  3. No task without acceptance criteria - How do we know it's done?
  4. No closure without documentation - Future agents need context
  5. Communication is constant - Stream reasoning, log everything
  6. The Auditor sees all - Quality monitored silently
  7. CEO approves major changes - Human-in-the-loop for critical decisions

Technology Stack

Layer Technology
API Framework FastAPI
Database PostgreSQL + SQLAlchemy (async)
Vector Store PostgreSQL + pgvector (in-house engine)
Cache/Queue Redis
RAG Engine in-house (asyncpg + pgvector, hybrid retrieval)
Embeddings qwen3-embedding:0.6b (Ollama)
Local LLM Ollama (glm-5.2:cloud)
Cloud LLM Claude API (Anthropic) + xAI Grok (official grok CLI, SuperGrok subscription)
Package Manager uv

Status

Core Infrastructure (Complete)

  • Data models (Pydantic)
  • Database ORM (SQLAlchemy async)
  • Task lifecycle state machine
  • Multi-agent workspace management
  • Agent prompts (25 agents)
  • Messaging API
  • Task API with full lifecycle
  • Git operations API
  • RAG/Knowledge base (in-house pgvector engine)
  • Agent orchestrator
  • CEO approval workflow
  • Pluggable agent providers (Claude Code + xAI Grok on the official grok CLI)
  • Inbound PR review (read-only PR-reviewer + CEO supersede/dismiss queue)
  • Self-healing CI loop for RoboCo's own repo (default-off, CEO-gated)
  • Business Goals tab with a live Company Scorecard (delivery, spend-vs-budget, lead time)

In Progress

  • Frontend panel (vendored under panel/, served through nginx on :3000)
  • Full agent autonomy testing

Security

Important

Do not expose RoboCo to the public internet as-is. It is designed to run on a trusted private network (homelab / LAN).

Agent authentication. Requests identify the caller with X-Agent-Id / X-Agent-Role headers. The orchestrator issues each spawned agent an HMAC token (X-Agent-Token, signed with ROBOCO_AGENT_AUTH_SECRET) that binds its id, role and team. Token enforcement is gated by ROBOCO_AGENT_AUTH_REQUIRED:

  • ROBOCO_AGENT_AUTH_REQUIRED unset/false (default): header-trust mode — the role headers are accepted without a token, so any client that can reach the API may claim any role (including ceo). The API logs a warning at startup in this mode. Acceptable only on a trusted network.
  • ROBOCO_AGENT_AUTH_REQUIRED=true: every request must carry a valid token; an agent cannot spoof another agent's role. The control panel keeps working because nginx — the only trusted hop between the browser and the API — injects the CEO token (X-Agent-Token) on /api and /ws, so the browser never holds the signing secret. Generate that token with make panel-token and set it as ROBOCO_PANEL_AGENT_TOKEN in .env before enabling secure mode.

WebSocket streams. Token enforcement is currently REST-only. The /ws/* endpoints authenticate by agent_id query param at most and do not yet validate X-Agent-Token, even in secure mode — nginx injects the token so the panel works, but a direct WebSocket connection that bypasses nginx is not rejected. In particular the operator stream /ws/system (rate-limit lifecycle + token-usage snapshots for the dashboard) is unauthenticated. These streams are read-only — no control surface, secrets, or task content — but treat the orchestrator port as trusted-network-only until WebSocket auth lands.

Secrets (the Fernet ROBOCO_ENCRYPTION_KEY, GitHub PATs) live encrypted in the database and in gitignored env files — never in the repo. Per-project git tokens are Fernet-encrypted at rest and never returned by the API.

License

Copyright (c) 2026 Renzo Franceschini

RoboCo is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See LICENSE for the full text.

The AGPL's network-use clause (section 13) means that if you run a modified version of RoboCo as a network service, you must make your modified source available to its users. This keeps the project open while preventing closed, hosted re-distributions.

Contributing

Contributions are welcome. All contributors must sign the Contributor License Agreement (CLA.md) — this is automated on your first pull request. See CONTRIBUTING.md for the workflow and why the CLA exists.

S
Description
No description provided
Readme AGPL-3.0
100 MiB
Languages
Python 80.8%
TypeScript 17%
HTML 0.8%
Shell 0.6%
JavaScript 0.3%
Other 0.5%