Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cff28d9
feat(core): executor catalog, interaction schemas, checkpoint vocabulary
hutusi Jul 22, 2026
7d2d204
feat(db): checkpoints, comments, iterations, agent bindings
hutusi Jul 22, 2026
51e7b97
feat(orchestration): agrippa/v2 — agent slots, checkpoint steps, boun…
hutusi Jul 22, 2026
2f6ad57
test(orchestration): compliance coverage for slots, checkpoints, loop…
hutusi Jul 22, 2026
fc7b30f
feat(executor-codex): OpenAI Codex CLI executor
hutusi Jul 22, 2026
6673a52
feat(worker): platform SCM service, codex registration, round-aware d…
hutusi Jul 22, 2026
0b6ee24
feat(api): checkpoint respond, comments, pending inbox, agent-slot ov…
hutusi Jul 22, 2026
e619dd1
feat(templates): requirement-delivery template + arbiter faber + open…
hutusi Jul 22, 2026
425aee3
feat(web): checkpoint interaction, run timeline, comments, agent pick…
hutusi Jul 22, 2026
845122e
docs: ADR-0010/0011, design docs, manual, changelog for requirement d…
hutusi Jul 22, 2026
8432022
fix(dev): repair the screenshot harness for invite-only auth and chec…
hutusi Jul 22, 2026
9687dd2
fix(orchestration): review-round correctness — diff base, strict arti…
hutusi Jul 23, 2026
b4c0555
fix(api): executor availability at submit; checkpoint panels present …
hutusi Jul 23, 2026
3785c13
fix(worker): idempotent pr.open, codex config isolation; review-fix docs
hutusi Jul 23, 2026
8afb151
fix(worker): demo executor makes a real workspace change for patch steps
hutusi Jul 23, 2026
e7ca49c
fix(worker): evidence integrity — sanitized paths, finalize commit, s…
hutusi Jul 23, 2026
fa1ddd4
fix(worker): defer runs for unregistered executors; doc consistency
hutusi Jul 23, 2026
a3ef5ba
fix(worker,orchestration): platform git distrusts the workspace; read…
hutusi Jul 23, 2026
0b4318d
docs: ADR amendments and design corrections for the round-3 review
hutusi Jul 23, 2026
eb93d5d
fix: harden platform git snapshot publishing
hutusi Jul 23, 2026
cbf360e
fix: address CodeRabbit review — test awaits, checkpoint evidence fal…
hutusi Jul 23, 2026
44abca0
docs: state the asymmetric auto-pass in the v2 changelog entry
hutusi Jul 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This document is the orientation map for contributors. The authoritative design

## Bird's-eye view

Agrippa runs agent-driven work for teams. A user submits a **task** (a task type + parameters) inside a **project**; the platform creates a **run**, queues it, and a **worker** executes it by walking the task type's **orchestration template** — a versioned, declarative YAML document describing phases, steps, human-approval checkpoints, model-selection rules, budgets, and an artifact contract. Each *agent step* is delegated to a pluggable **executor** (Claude Agent SDK first); everything structural stays in the platform's own engine. Progress streams live to the browser; deliverables land as downloadable artifacts.
Agrippa runs agent-driven work for teams. A user submits a **task** (a task type + parameters) inside a **project**; the platform creates a **run**, queues it, and a **worker** executes it by walking the task type's **orchestration template** — a versioned, declarative YAML document describing phases (and, since agrippa/v2, bounded **loops**), steps, human **checkpoints** (approvals, question forms, review gates), **agent slots** (implementer/reviewer bound to a faber + executor per run), model-selection rules, budgets, and an artifact contract. Each *agent step* is delegated to a pluggable **executor** (Claude Agent SDK and the OpenAI Codex CLI); everything structural — including the platform-side git branch/push/PR write-path — stays in the platform's own engine. Progress streams live to the browser (agent output, checkpoint cards, team comments); deliverables land as downloadable artifacts.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

```
Browser (SPA) ──REST──▶ api ──singleton-keyed send──▶ pg-boss (Postgres)
Expand All @@ -25,21 +25,22 @@ Browser (SPA) ──REST──▶ api ──singleton-keyed send──▶ pg-bos
| `packages/orchestration` | The platform brain: `compile.ts` (YAML → validated compiled JSON), `expression.ts` (the deliberately non-Turing-complete `${...}` language), `engine/engine.ts` (the run loop), `queue.ts` (pg-boss factory), `engine/bus.ts` + `redis-bus.ts` (live-event fan-out), `resolve.ts` (submit-time param validation + model-role resolution), `seed-builtins.ts`. |
| `packages/executor-core` | The `Executor` interface and normalized event stream (ADR-0005), `BudgetMeter`, and `FakeExecutor` — the compliance fixture every executor must satisfy. |
| `packages/executor-claude` | Maps a step request onto Claude Agent SDK `query()` options and SDK messages back onto normalized events; scans `.agrippa/artifacts/` on success. |
| `packages/executor-codex` | Wraps the OpenAI Codex CLI (`codex exec --json`): JSONL events → normalized events, native OS sandbox for containment, fenced-json artifact synthesis for read-only steps (ADR-0011). |
| `packages/i18n` | en/zh-CN resources by namespace + the server-side error-message lookup; a parity test keeps locales in lockstep. |
| `apps/api` | Hono: better-auth, RBAC middleware, registries, template publishing, task submission (grant + quota gating), run lifecycle, approvals, artifacts, SSE, audit log. Serves the built SPA in production. Never imports executors. |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
| `apps/worker` | pg-boss consumers around the engine; real deps: `GitWorkspaceManager` (clone with scrubbed credentials), `DbResourceMaterializer` (skills → disk, MCP + secrets), `DiskArtifactStore`, `DemoExecutor` (token-free), approval-expiry handler, reconciliation sweeper. |
| `apps/worker` | pg-boss consumers around the engine; real deps: `GitWorkspaceManager` (clone with scrubbed credentials), `GitScmService` (branch/push/PR via provider REST — ADR-0011), `DbResourceMaterializer` (skills → disk, MCP + secrets), `DiskArtifactStore`, `DemoExecutor` (token-free, loop-round-aware), checkpoint-expiry handler, reconciliation sweeper. Registers executors and asserts them against core's `EXECUTOR_CATALOG` at boot. |
| `apps/web` | React SPA: TanStack Router/Query, shadcn/ui (GitLab-style sidebar shell, indigo/violet tokens, light+dark), react-i18next. The load-bearing piece is `TaskParamsForm` — rendered from compiled template inputs, so new task types need zero frontend work. |
| `templates/` | Builtin `agrippa/v1` templates (6), shared subagent prompts, builtin skills. Compiled + published at boot, checksum-guarded. |
| `templates/` | Builtin templates (6 × agrippa/v1 + the agrippa/v2 `swdev.requirement-delivery` flagship), shared subagent prompts, builtin skills. Compiled + published at boot, checksum-guarded. |

Dependency direction is enforced by `scripts/check-deps.ts` (runtime deps only).

## Key flows

**Submit → run.** `POST /projects/:id/tasks` validates params against the compiled input schema (the same schema the SPA rendered the form from), verifies each `repoRef` is owned by the project, resolves model roles → concrete granted models (frozen into `runs.model_resolution`), pins the authorized skills/MCP into `runs.resource_manifest` (required grants enforced, optional included only when granted), checks hard-stop quota headroom, then inserts task+run in one transaction and sends a pg-boss job keyed by run id. A worker sweeper re-enqueues stragglers (and runs left paused by a lost approval-resume), so a run can never be stranded nor double-queued.

**Engine loop.** The engine (worker-side) walks phases/steps: `when:` conditions, optional-resource skips, per-step retries, budget checks at every boundary. Agent steps stream normalized executor events which the engine persists to `run_events` (per-run monotonic `seq`), mirrors to the bus, and projects into `run_steps`/`token_usage`/`artifacts`. At the end it enforces the artifact contract — *succeeded* always means the contracted outputs exist.
**Engine loop.** The engine (worker-side) walks flow nodes (phases and bounded loops): `when:` conditions, optional-resource skips, per-step retries, budget checks at every boundary. Loop rounds key every row by `(stepId, iteration)` and derive the resume iteration from persisted rows. Agent steps resolve their slot's executor + faber from `runs.agent_bindings` and stream normalized executor events which the engine persists to `run_events` (per-run monotonic `seq`), mirrors to the bus, and projects into `run_steps`/`token_usage`/`artifacts`. System steps cover checkout plus the platform git write-path (`git.branch`/`git.push`/`pr.open` — the PR body includes accepted-findings waivers). At the end it enforces the artifact contract — *succeeded* always means the contracted outputs exist (latest loop iteration wins).

**Approvals.** An approval checkpoint records a pending row, flips the run to `waiting_approval`, and **completes the job** (no held worker slot). The API decision re-enqueues; the engine resumes at the gated phase. Expiry is a scheduled pg-boss job applying the template's `onTimeout`.
**Checkpoints.** A checkpoint step (approval / question form / review gate) records a pending row with a payload snapshot, flips the run to `waiting_approval`, and **completes the job** (no held worker slot); question forms and review gates auto-pass when their source artifact is empty. The API respond endpoint validates the answer against the snapshot, stores a structured `response` (which re-enters the run as the `checkpoints.<id>` expression root), and re-enqueues; the engine resumes at the gated step. Expiry is a scheduled pg-boss job applying the template's `onTimeout`. Run comments ride the same event stream (`comment.added`).

**Crash-resume.** Unexpected engine errors rethrow → pg-boss retries → the engine resumes: succeeded steps skip, a stale `running` step row is marked failed and re-attempted, and the `BudgetMeter` rebuilds from persisted `token_usage` rows keyed per attempt — no double counting. This exact path is exercised by a mid-step crash test.

Expand All @@ -63,7 +64,7 @@ Dependency direction is enforced by `scripts/check-deps.ts` (runtime deps only).
|---|---|
| Change the template format | `packages/orchestration/src/template-schema.ts` + `compile.ts`, then `docs/design/02` |
| Touch run execution semantics | `packages/orchestration/src/engine/engine.ts` + its integration test (the compliance suite) |
| Add/modify an executor | `packages/executor-core/src/types.ts` (contract), `executor-claude` (reference), ADR-0005 |
| Add/modify an executor | `packages/executor-core/src/types.ts` (contract), `executor-claude`/`executor-codex` (references), core `EXECUTOR_CATALOG`, ADR-0005/0011 |
| Add an API endpoint | `apps/api/src/routes/`, schema in `packages/core/src/schemas.ts`, test in `apps/api/src/test/` |
| Change the data model | `packages/db/src/schema/`, then `bunx drizzle-kit generate` in `packages/db` |
| Understand a past decision | `docs/adr/` — 0005 (executor granularity) and 0003 (pg-boss) carry the most weight |
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ All notable changes to Agrippa are documented here. The format follows

### Added

- **Requirement-delivery workflow** — the new `swdev.requirement-delivery` task type takes a natural-language requirement all the way to a reviewed pull request: a clarify loop where the implementer asks structured questions (with recommended answers; auto-continues when it has none), a plan loop whose approval supports *request changes* with the comment fed back into the revision, implementation on a platform-created branch, a cross-agent **review-fix loop** (implementer = Claude Code / Forge, reviewer = OpenAI Codex / the new **Arbiter** faber) where each round the user picks findings to fix or accepts the rest (zero findings auto-pass), and a publish phase that pushes and opens the PR platform-side — with any accepted findings listed in the PR body as explicit waivers, including who accepted them. An extra sign-off appears only when the loop exhausts right after a fix that was never re-reviewed.
- **`agrippa/v2` template format** (ADR-0010) — agent slots (named implementer/reviewer roles binding a faber + executor, user-overridable at submit with capability and provider checks), checkpoint *steps* in three kinds (`approval` incl. request-changes, `input` question forms, `review-gate` findings decisions — the latter two auto-pass on empty sources), bounded `loop` nodes (static `maxIterations`, `until` conditions), platform SCM system actions (`git.branch`/`git.push`/`pr.open`), and new expression roots (`checkpoints.<id>`, `artifacts.<key>`). v1 templates keep working unchanged through a pure compile-time upgrade; the whole engine compliance suite passes through it, plus new suites for slots, checkpoints, loops, and SCM.
- **OpenAI Codex executor** (`packages/executor-codex`, ADR-0011) — wraps `codex exec --json` (event shapes pinned against codex-cli 0.145.0): normalized event mapping with cache-aware usage splitting, containment via Codex's native OS sandbox (read-only / workspace-write, network off, no interactive escalation), env through the shared allow-list scrubber, and fenced-json artifact synthesis for read-only reviewer steps. Registered only when the CLI probe and auth succeed; every registered executor is asserted against the new static `EXECUTOR_CATALOG` in core at worker boot.
- **Checkpoint interaction API + team collaboration** — `POST /runs/:id/checkpoints/:checkpointId/respond` (kind-discriminated: decision/answers/finding selections, validated against the pending row's snapshot; CAS + event + audit in one transaction), a generalized cross-project `GET /checkpoints/pending` "waiting on you" inbox, and **run comments** (`GET`/`POST /runs/:id/comments`) that commit together with their `comment.added` run event so the live timeline and the thread can never disagree. Task submission accepts per-slot `agents` overrides; model resolution is per-slot and provider-filtered (a Codex slot without a granted OpenAI model fails at submit, not mid-run). The legacy `/approvals` decide routes are removed.
- **Run timeline UX** — the run detail page's default tab is now a conversational timeline built from the replayed SSE stream: phase headers with loop-round chips, streaming agent turns tagged with each slot's persona and engine, inline checkpoint cards (question forms with one-click recommendations; findings tables with severity badges and explicit accept-remaining confirmation; request-changes on loop approvals), teammate comments with a pinned composer, and a PR card at the end. The submit page gains agent-slot pickers; the phases rail, budget/meta cards, and inbox are round- and kind-aware. OpenAI codex model rows join the seed (verify ids/pricing per deployment).

### Changed

- **`approvals` table → `checkpoints`** (data-preserving rename) with `kind`, `iteration`, and a structured `response`; `run_steps` and `artifacts` gain `iteration`; `runs` gain `agent_bindings` and `work_branch`; new `run_comments` table (migration `0005_requirement-delivery`). Engine events rename `approval.required/decided` → `checkpoint.required/decided` and add `loop.*`, `branch.*`, `pr.opened`, `comment.added`.
- **Demo mode hardening** — when `AGRIPPA_EXECUTOR=fake`, every agent slot binds to the demo executor (a demo install must never silently route a slot to a real, key-consuming engine), `AGRIPPA_SCM=fake` fabricates branch/push/PR, and the demo executor is loop-round-aware (questions/findings in round 1, clean in round 2) so the delivery workflow demos end-to-end without tokens.

- **Invite-only onboarding; self-registration closed** — `POST /api/auth/sign-up/*` is now guarded and returns `403 registration_closed` (localized). The only ways to join the org are the new bootstrap-admin script (`bun --env-file=../../.env.local apps/api/src/cli/bootstrap-admin.ts`, reads `AGRIPPA_BOOTSTRAP_EMAIL`/`PASSWORD`, idempotent, creates the first `org_admin`) and the invitation flow: `org_admin` calls `POST /api/v1/invitations` to get a one-time `?token=…` link (token stored hashed — sha256 — so a DB leak can't be replayed); the invitee opens `/accept-invite?token=…` (public, no session), sets name + password, and is created as `org_member` via direct `users`+`accounts` insert (`hashPassword` from `better-auth/crypto`), then signs in through the normal endpoint. `GET /api/v1/invitations` lists, `DELETE /api/v1/invitations/:id` revokes. New `invitations` table + migration `0004_invitations`. The SPA login page drops the sign-up mode; a new `/accept-invite` page and an Admin → Members invite-management page are added. No email infrastructure exists — invite links are returned to the admin to share out-of-band. The `user.create` first-user→admin hook is retained as a safety net but superseded by `bootstrap-admin`.
- **`APT_MIRROR` build arg for the worker image** — `infra/Dockerfile.worker` now accepts an optional `APT_MIRROR` build arg that swaps Debian apt to a closer mirror before `apt-get install` (the worker image needs git/ripgrep/bubblewrap). `docker-compose.yml` threads it through as `build.args.APT_MIRROR: ${APT_MIRROR:-}`, documented in `infra/env/.env.example`. No-op when unset; set `APT_MIRROR=https://mirrors.aliyun.com` (or similar) for hosts where `deb.debian.org` is slow or blocked.

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ Agrippa is a team-oriented agent work platform. Teams collaborate in **projects*
## Three layers

1. **Scenario layer** — a task catalog organized by work scenario; forms are auto-generated from template parameter schemas.
2. **Orchestration layer** — Fabri execute runs by following orchestration templates: phases, steps, human-approval checkpoints, model-selection rules, budgets. Engines are pluggable; the first executor is the Claude Agent SDK.
2. **Orchestration layer** — Fabri execute runs by following orchestration templates: phases, bounded loops, steps, human checkpoints (approvals, question forms, review gates), model-selection rules, budgets. Engines are pluggable **per agent slot** — one run can pair a Claude Code implementer with an OpenAI Codex reviewer, as the flagship *Requirement Delivery* workflow does (clarify → plan → implement → review-fix loop → platform-opened PR).
3. **Resource layer** — governed registries for models, sub-agents, Skills, MCP servers, and templates, with registration, immutable versioning, and project-level permission grants.

Projects are the resource scope and billing boundary: enabled Skills/MCP/models, token budget & quota, connected repos and docs.

## Status

M1 implemented — all three layers work end to end. See the [M1 plan](docs/plan/m1-plan.md) for what shipped.
M1 implemented — all three layers work end to end (see the [M1 plan](docs/plan/m1-plan.md)), plus the agrippa/v2 requirement-delivery workflow: multi-agent implement/review loops with structured human checkpoints, team comments, and platform-side pull requests ([CHANGELOG](CHANGELOG.md)).

## Getting started

Expand All @@ -40,7 +40,7 @@ Self-registration is **closed** — create the first admin out-of-band, then sig
bun apps/api/src/cli/bootstrap-admin.ts # idempotent; creates the first org_admin
```

Sign in at :5173 with that account, create a project, grant models/skills under Settings → Resources, then submit a task from the catalog. To invite teammates (the only other way in), use Admin → Members. For real runs set `AGRIPPA_EXECUTOR=claude-agent-sdk` and `ANTHROPIC_API_KEY` in `.env.local` — and keep the file: `AGRIPPA_SECRET_KEY` encrypts credentials you store, so regenerating it orphans them (see [CONTRIBUTING.md](CONTRIBUTING.md)).
Sign in at :5173 with that account, create a project, grant models/skills under Settings → Resources, then submit a task from the catalog. To invite teammates (the only other way in), use Admin → Members. For real runs set `AGRIPPA_EXECUTOR=claude-agent-sdk` and `ANTHROPIC_API_KEY` in `.env.local` — and for the Codex reviewer slot, install the Codex CLI and set `OPENAI_API_KEY`. `AGRIPPA_SCM=fake` fabricates branch/push/PR for token-free demos of the delivery workflow. Keep the file: `AGRIPPA_SECRET_KEY` encrypts credentials you store, so regenerating it orphans them (see [CONTRIBUTING.md](CONTRIBUTING.md)).

**Self-hosted** (Docker):

Expand All @@ -67,7 +67,7 @@ sudo /opt/agrippa/infra/vm/install.sh # idempotent; updates: infra/vm/depl

## Tech stack

TypeScript · Bun workspaces monorepo · Hono (REST + SSE) · Vite + React + TailwindCSS + shadcn/ui · Drizzle + Postgres · pg-boss · Redis (pubsub) · better-auth · i18next (en / zh-CN) · Claude Agent SDK (first executor) · Docker Compose or systemd VM (self-hosted)
TypeScript · Bun workspaces monorepo · Hono (REST + SSE) · Vite + React + TailwindCSS + shadcn/ui · Drizzle + Postgres · pg-boss · Redis (pubsub) · better-auth · i18next (en / zh-CN) · Claude Agent SDK + OpenAI Codex CLI (executors) · Docker Compose or systemd VM (self-hosted)

---

Expand All @@ -78,11 +78,11 @@ Agrippa(硅基工坊)是一个面向团队的智能体工作平台。团队
### 三层架构

1. **场景层** —— 按工作场景组织的任务目录;提交表单由模板参数 Schema 自动生成。
2. **编排层** —— 硅基人依照编排模板执行任务:阶段与步骤、人工审批节点、模型选择规则、预算限制。执行引擎可插拔,首个执行器为 Claude Agent SDK。
2. **编排层** —— 硅基人依照编排模板执行任务:阶段与有界循环、步骤、人工检查点(审批、问题表单、评审关卡)、模型选择规则、预算限制。执行引擎按**代理位**可插拔——同一次执行可以让 Claude Code 做实现者、OpenAI Codex 做评审者,旗舰工作流「需求交付」正是如此(澄清 → 规划 → 实现 → 评审-修复循环 → 平台创建 PR)。
3. **资源层** —— 模型、子智能体、技能、MCP 服务与编排模板的受管注册表:注册、不可变版本、项目级授权。

项目是资源与计费边界:项目级启用技能/MCP/模型、Token 预算与配额、关联代码仓库与文档。

### 当前状态

设计阶段——请阅读上方设计文档;实现按 [M1 计划](docs/plan/m1-plan.md) 推进。
M1 已实现——三层架构端到端可用(见 [M1 计划](docs/plan/m1-plan.md)),并已支持 agrippa/v2 需求交付工作流:多代理实现/评审循环、结构化人工检查点、团队评论与平台侧 PR(见 [CHANGELOG](CHANGELOG.md))。
Loading