AOP Software Delivery Plugin for DeepSeek Harness
August 23, 2026 · View on GitHub
@get-aop/aop-plugin is a software delivery workflow plugin for DeepSeek Harness and Cordis. It automates the multi-agent software engineering lifecycle:
Each role runs with independent context, a configurable provider/model route, tailored toolsets, and rigid evaluator gates. Per-role reasoning or thinking effort is intentionally not exposed: current Harness cannot propagate it reliably.
The published client is a lazy Harness module (window.__ModuleLoader__.load). Its Tailwind utilities use the aop: prefix, semantic tokens are scoped to the AOP card, and Radix content is mounted in an AOP-owned portal root; the Host document is not reset.
Slash commands
/aop <objective>— plan, implement, review, and browser-test the objective; findings ping-pong back to implementation until both evaluators pass./aopy <objective>— AOP YOLO: the same workflow, then a Ship pass opens a pull request, verifies CI/CD, fixes conflicts and issues, and merges automatically.
Key Features
- Evaluator-Gated Ping-Pong: Adversarial code reviewer and independent browser QA engineer reject flawed implementations. Any reported finding forces an implementation pass with an exact disposition requirement.
- Review Precedes QA: Any code modification must pass code review with 0 findings before Browser QA can execute.
- Mandatory Retesting: QA tracks every prior defect ID and verifies observable resolution before certification.
- Verified Browser QA: Browser QA requires real navigation to the QA target (the given
qaUrl, or one it discovers and declares itself) followed by post-navigation browser interaction and snapshot evidence. Evidence is pinned to the declared target — navigation and observed evidence must settle against exactly that URL. - YOLO Ship Pass (
/aopy,mode: yolo): after QA passes, the ship pass commits and pushes a branch, opens a PR, verifies CI with bounded polling, fixes conflicts and CI failures, and merges automatically — using the implementation role's writer tools. Honest blockers (no remote, no push permission, no CI, unresolvable conflict) stop the run instead of inventing a merge. - Model Routing: Configure distinct models/providers per stage:
- Plan:
sol-xhigh(deep reasoning architecture) - Implementation:
deepseek-v4-flash-max(fast, focused coding writer) - Review:
fable-5-max(adversarial code review) - Browser QA:
sol-medium(browser and UI verification)
- Plan:
- Safe Isolation: Evaluators are strictly limited to
readtools. Only the implementation role (and its ship pass) possesses workspacewriteaccess.
State Machine Workflow
stateDiagram-v2
[*] --> Plan: Objective / Ticket
Plan --> Implementation: Ready Plan (ACs defined)
Implementation --> Review: Changes Made + Verified
Review --> Implementation: Changes Required (Findings)
Review --> QA: Pass (0 Review Findings)
QA --> Implementation: Changes Required (QA Defects)
QA --> Ship: Pass (All ACs Verified) — yolo mode only
Ship --> Completed: PR Opened, CI Green, Merged
Ship --> Blocked: No Remote / No CI / Unresolvable Conflict
QA --> Completed: Pass (All ACs Verified)
Plan --> Blocked: External Dependency
Implementation --> Blocked: Blocker Reported
Review --> Blocked: Blocker Reported
QA --> Blocked: Blocker Reported
Harness compatibility
The Host workflow requires the session-backed subagent, tool-access metadata,
workspace-access classification, and child-result validation contracts that
are present on the latest DeepSeek Harness default branch but not in the
published 0.1.0-rc.8 packages. Users must clone and build the latest Harness
source. The source tree may still report an rc.8 package version, so the plugin
also performs a runtime capability gate and fails loudly instead of silently
dropping evaluator isolation or QA evidence validation.
Installation & Configuration
1. Build the latest Harness source
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
git pull --ff-only
pnpm install --frozen-lockfile
pnpm build
Do not substitute the npm-published rc.8 CLI for this source build.
2. Install the plugin into the web profile
From the cloned Harness repository:
node apps/cli/lib/bin.js plugin --profile web add @get-aop/aop-plugin
3. Configure in cordis.yml
Mount the plugin in your cordis.yml profile or overlay:
- id: aop-delivery
name: '@get-aop/aop-plugin'
config:
subagentProvider: spawn
maxCycles: 8
maxFindings: 64
maxArtifactChars: 32768
maxResultChars: 262144
runTimeoutMs: 3600000
phaseTimeoutMs: 1800000
roles:
plan:
provider: opencode-go
model: deepseek-v4-pro
tools:
- name: read
access: read
- name: grep
access: read
- name: glob
access: read
implementation:
provider: opencode-go
model: deepseek-v4-flash
toolPresentation: native
tools:
- name: read
access: read
- name: write
access: write
- name: edit
access: write
- name: bash
access: write
- name: grep
access: read
- name: glob
access: read
review:
provider: kimi-coding
model: k3
tools:
- name: read
access: read
- name: grep
access: read
- name: glob
access: read
qa:
provider: opencode-go
model: deepseek-v4-flash
tools:
- name: read
access: read
- name: browser_navigate
access: read
browserNavigation: true
- name: browser_snapshot
access: read
browserEvidence: true
- name: browser_click
access: read
browserEvidence: true
- name: browser_fill
access: read
browserEvidence: true
Settings UI and lifecycle
The smallest bootstrap is an entry with an empty config:
- id: aop-delivery
name: '@get-aop/aop-plugin'
config: {}
The entry config is the Cordis base layer for the aop-delivery Host settings namespace. The Settings card edits only the user layer. A field reset emits a nested unset, so it re-inherits the entry/base value (or the safe default); Reset all clears every user override. Save sends one revision-fenced settings.mutate request containing all staged path operations. Conflicts, read-only Hosts, unavailable namespaces, and Host rejection preserve the draft instead of silently discarding it.
Settings apply to the next aop_delivery invocation. Each invocation resolves and snapshots the current settings exactly once, so a settings commit cannot change an in-flight workflow. Provider/model choices are refreshed from forwarded llm.models events; custom provider and model identifiers remain available when a catalog is unavailable. Tool names are editable structured grants because Harness has no tool-catalog API.
All workflow policy fields and every role's provider, model, tool presentation, tools, access, browser-navigation, and QA-evidence flags are represented. Reasoning/thinking effort is deliberately absent until Harness can propagate it end to end.
Tool API
aop_delivery (or delivery_workflow)
Invoked by an agent or user to execute the complete delivery lifecycle:
| Parameter | Type | Required | Description |
|---|---|---|---|
objective | string | Yes | The complete implementation objective or ticket. |
qaUrl | string | No | Absolute HTTP(S) target URL for browser QA. When omitted, QA discovers the deliverable itself — it inspects the workspace (package.json scripts, README, plan acceptance criteria) to find how the app runs and which URL it serves, and declares it in the QA artifact's discoveredUrl. Browser evidence is always pinned to one concrete target (given or discovered). |
qaInstructions | string | No | Concrete browser behaviors, interactions, and expected outcomes. When omitted, QA derives them from the plan's acceptance criteria and reports them under QA-INSTRUCTIONS. |
maxCycles | number | No | Optional implementation-pass ceiling (bounded by deployment policy). |
mode | string | No | standard (default) or yolo. yolo adds the Ship pass after QA passes: pull request, CI verification, conflict/issue fixes, automatic merge. |
Ship pass trust boundary: the ship pass uses the implementation role's writer tools (git/gh via bash) on the real repository. It merges only after CI checks report green; external outcomes (PR state, CI results, merge) are read from the repository's actual tooling, and the run terminates with a concrete blocker instead of fabricating a merge it cannot perform.
Wall-clock guards: runTimeoutMs cancels the whole run; phaseTimeoutMs cancels the whole run when any single evaluator phase exceeds it (Plan/Review/QA, armed via the workflow/phase event stream). The Implementation and Ship phases are exempt from the phase cap — they are the only phases that legitimately drive external pipelines (CI, releases) — and are bounded by runTimeoutMs alone.
Discovery-mode trust boundary: when
qaUrlis omitted, the target is declared by the QA model in the artifact'sdiscoveredUrl. The workflow enforces that navigation and evidence are pinned to exactly that declared URL (no navigation elsewhere can certify evidence), but it cannot verify that the declared URL is genuinely the deliverable — target authenticity is trusted to the QA model. For strict environments, always pass an explicitqaUrl.
Desktop apps (Electron etc.): QA is read-only and cannot start the app under test. The implementation phase (the only role with shell access) is instructed to start the deliverable's dev server or preview path in the background and report it as a URL: http://... verification entry; QA uses that URL first. If nothing is running, QA probes common dev ports once and returns blocked naming exactly what must be started and how.
About AOP
Agents Operating Platform (AOP) is a local-first orchestrator for autonomous coding agents.
- Website: getaop.com
- GitHub: github.com/get-aop
License
MIT © AOP contributors