chore(release): 0.7.0

Roll up everything since 0.6.0 into the 0.7.0 CHANGELOG and bump the version
(pyproject / __init__ / config.app_version). Rewrite the stale Unreleased Grok
entry — which described the now-deleted opencode runtime — to the shipped
reality: Grok agents on xAI's official grok CLI on a SuperGrok subscription,
plus the token auto-refresh, the self-healing CI loop, the Company Scorecard,
and the pr-reviewer / observability / usage / path-injection fixes. Also folds
the uv.lock claude-agent-sdk spec sync (>=0.2.105) merged via #216.
This commit is contained in:
Renn F
2026-06-19 10:35:04 +02:00
parent f2e787c577
commit 01e082ff63
8 changed files with 19 additions and 10 deletions
+11 -2
View File
@@ -4,11 +4,20 @@ All notable changes to RoboCo are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [0.7.0] - 2026-06-19
### Added ### Added
- **Pluggable agent providers + a Grok (xAI) backend.** A new `roboco/llm/providers/` seam (an `AgentProvider` lifecycle ABC + a `ProviderRegistry` keyed by `ModelProvider`) lets the orchestrator drive agent backends other than Claude Code. The first is `GrokProvider` for xAI's `grok-build-0.1`: xAI is OpenAI-compatible only (no Anthropic-Messages endpoint), so a Grok agent runs an OpenAI-protocol runtime pointed at `https://api.x.ai/v1` rather than the `ANTHROPIC_BASE_URL` injection the other providers use — and it reuses the orchestrator's existing mount/auth assembly, so it gets the same MCP gateway + tool-manifest wiring as every other agent by construction (and passes its prompt via env, never an argv positional). The change is purely additive: only `GROK` routes through the registry; Anthropic / Ollama Cloud / self-hosted spawns are untouched. Includes the `grok` enum value (migration 038), a seeded Grok provider row (migration 039), a `grok-build-0.1` catalog entry, and `GET/PUT /api/providers/grok-key` + a Settings panel card to store the xAI key (Fernet-encrypted, reusing the existing provider-key machinery). Ships the full native runtime: a first-class `roboco-agent-grok` image (built `FROM` agent-base, adds opencode; wired into both compose files, the registry compose, and the release workflow) whose entrypoint renders an `opencode.json` at spawn — translating RoboCo's MCP gateway servers into opencode's config and declaring the xAI provider — then runs opencode. KNOWN PARITY GAP: RoboCo's bash-guard (PAT-scrub) and transcript-based usage/cost capture are Claude Code hooks that do not transfer to the opencode runtime; the `bash` permission is operator-tunable so a deployment can fail closed until a security/usage-parity opencode plugin lands. That plugin and live end-to-end validation are the remaining work to finalize with xAI. - **Grok agents on xAI's official `grok` CLI, on a SuperGrok subscription.** A new `roboco/llm/providers/` seam (an `AgentProvider` lifecycle ABC + a `ProviderRegistry` keyed by `ModelProvider`) lets the orchestrator drive agent backends other than Claude Code, and the first is Grok — running xAI's official `grok` CLI authenticated by a **SuperGrok subscription** rather than a metered API key, so a Grok workforce can't stall mid-task on out-of-credits. It reaches parity with the Claude path by construction: the same MCP gateway + tool-manifest wiring, per-role tool removal and git-operation deny rules, a prompt-injection guard on the task prompt, headless tool auto-approval, and per-agent token/cost capture from the grok session store. It covers both one-shot delivery roles and the interactive Intake (Prompter) and Secretary chats (per-turn `grok -p` with session resume, streamed turn-by-turn). The change is purely additive only `GROK` routes through the registry; Anthropic / Ollama Cloud / self-hosted spawns are untouched — and ships migration 038 (the `grok` enum) + 039 (the seeded provider row), first-class `roboco-agent-grok` / `-prompter` / `-secretary` images wired into all three compose files and the release workflow, and a Settings provider card.
- **SuperGrok token auto-refresh.** The grok access token has a fixed ~6h server-set TTL and the CLI cannot refresh it headlessly — on an expired token it hangs forever at an interactive login prompt — so the orchestrator now mints a fresh token from the offline-access refresh token (xAI's OIDC `refresh_token` grant) before expiry and rewrites the shared `auth.json` in place, keeping every Grok agent's credential live with no recurring manual `grok login`. As a backstop the agent entrypoint refuses to start (exit 78) on a missing or expired token instead of hanging.
- **Self-healing CI loop (default-off).** RoboCo can now watch its own repository's CI and, on a detected regression, open a fix task that is held out of dispatch until the CEO approves it — then dispatch it through the normal delivery flow, so the company repairs its own breakages. It is dormant by default and armed from two Feature-Flags panel toggles; the CI signal is scoped to a single named workflow, and task origination is bounded by rolling and per-cycle caps so it can't flood the backlog.
- **Company Scorecard.** A company scorecard on the panel's Business Goals tab.
### Fixed
- **The PR-reviewer is no longer wedge-killed before it can post a review.** `pr_review_claim` now seeds the claim heartbeat like every other claim path; without it a Grok reviewer was treated as a silent (NULL-heartbeat) wedged container and killed before it could call `post_pr_review`, churning the task back to pending in a respawn loop.
- **Grok one-shot runs are observable, and their usage is captured.** The entrypoint streams agent activity to the container log live (`--output-format streaming-json`) instead of buffering it to a file until the run ends, and per-agent token/cost is read from the grok session store's actual cumulative-total field (it was silently reading `$0`).
- **Path-injection hardening of the Grok usage directory.** The agent id is validated and reduced to a single safe path component before it is used to build the per-agent usage path, on both the write/mount and finalize-read sides.
## [0.6.0] - 2026-06-17 ## [0.6.0] - 2026-06-17
+1 -1
View File
@@ -120,7 +120,7 @@ Choose the registry and version with two env vars (defaults shown):
```bash ```bash
ROBOCO_REGISTRY=ghcr.io/rennf93 # or docker.io/renzof93 ROBOCO_REGISTRY=ghcr.io/rennf93 # or docker.io/renzof93
ROBOCO_VERSION=latest # or a pinned release, e.g. 0.6.0 ROBOCO_VERSION=latest # or a pinned release, e.g. 0.7.0
``` ```
The orchestrator spawns the matching pre-built agent images on demand — no build toolchain or source compile on your host. The orchestrator spawns the matching pre-built agent images on demand — no build toolchain or source compile on your host.
+1 -1
View File
@@ -41,7 +41,7 @@ docker compose -f docker-compose.registry.yml up -d
docker compose -f docker-compose.registry.yml logs -f orchestrator docker compose -f docker-compose.registry.yml logs -f orchestrator
``` ```
Choose the registry and version with `ROBOCO_REGISTRY` (`ghcr.io/rennf93` or `docker.io/renzof93`) and `ROBOCO_VERSION` (`latest` or a pinned release such as `0.6.0`). The orchestrator pulls and spawns the matching pre-built agent images on demand. Choose the registry and version with `ROBOCO_REGISTRY` (`ghcr.io/rennf93` or `docker.io/renzof93`) and `ROBOCO_VERSION` (`latest` or a pinned release such as `0.7.0`). The orchestrator pulls and spawns the matching pre-built agent images on demand.
### Option B — Build from source ### Option B — Build from source
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "roboco-panel", "name": "roboco-panel",
"version": "0.6.0", "version": "0.7.0",
"private": true, "private": true,
"packageManager": "pnpm@10.25.0", "packageManager": "pnpm@10.25.0",
"scripts": { "scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "roboco" name = "roboco"
version = "0.6.0" version = "0.7.0"
description = "AI Agents Company - A virtual organization of AI agents functioning as a software development workforce" description = "AI Agents Company - A virtual organization of AI agents functioning as a software development workforce"
authors = [ authors = [
{name = "Renzo Franceschini", email = "rennf93@users.noreply.github.com"} {name = "Renzo Franceschini", email = "rennf93@users.noreply.github.com"}
+1 -1
View File
@@ -5,7 +5,7 @@ A virtual organization of 22 AI agents + 1 human CEO,
designed to operate as a complete software development workforce. designed to operate as a complete software development workforce.
""" """
__version__ = "0.6.0" __version__ = "0.7.0"
# Core exports # Core exports
from roboco.config import settings from roboco.config import settings
+2 -2
View File
@@ -28,7 +28,7 @@ class Settings(BaseSettings):
# ========================================================================== # ==========================================================================
# Application # Application
# ========================================================================== # ==========================================================================
app_version: str = "0.6.0" app_version: str = "0.7.0"
debug: bool = False debug: bool = False
environment: str = Field( environment: str = Field(
default="development", pattern="^(development|staging|production)$" default="development", pattern="^(development|staging|production)$"
@@ -488,7 +488,7 @@ class Settings(BaseSettings):
agent_image_tag: str = Field( agent_image_tag: str = Field(
default="", default="",
description=( description=(
"Tag for pre-built agent images (e.g. 'latest' or '0.6.0'). Empty " "Tag for pre-built agent images (e.g. 'latest' or '0.7.0'). Empty "
"leaves the tag implicit (':latest'); only meaningful with " "leaves the tag implicit (':latest'); only meaningful with "
"agent_image_registry set." "agent_image_registry set."
), ),
Generated
+1 -1
View File
@@ -3056,7 +3056,7 @@ requires-dist = [
{ name = "anthropic" }, { name = "anthropic" },
{ name = "asyncpg" }, { name = "asyncpg" },
{ name = "bandit", marker = "extra == 'dev'" }, { name = "bandit", marker = "extra == 'dev'" },
{ name = "claude-agent-sdk", specifier = ">=0.2.101" }, { name = "claude-agent-sdk", specifier = ">=0.2.105" },
{ name = "cryptography" }, { name = "cryptography" },
{ name = "deptry", marker = "extra == 'dev'" }, { name = "deptry", marker = "extra == 'dev'" },
{ name = "factory-boy", marker = "extra == 'dev'" }, { name = "factory-boy", marker = "extra == 'dev'" },