Run and record the HarnessX dependency dry-run audit and assess blueprint alignment with the author's DocuHarnessX, to steer OpenUltraSAST's HarnessX adoption from opencode/claude-code. - dependency-audit.md: records the realized transitive graph (118 packages from 30 mandatory HarnessX deps). Key finding: every heavy backend (docker/e2b/ playwright/office-PDF) is lazily imported and the gateway is a separate dist, so the tree is an install-time (not runtime) cost; ~55-60 packages are dead weight for SAST. Decision: ACCEPT as the optional SHA-pinned extra openultrasast[harnessx] (core stays zero-dep; lazy heavy imports; matches DocuHarnessX precedent), with a fully-specified vendored lean subset as the triggered fallback and upstream dependency-extras as the preferred long-term slimming path. Records the security-tool residual risks (browser binary, docker socket, web server, CVE surface) and their mitigations. - blueprint-alignment.md: DocuHarnessX <-> OpenUltraSAST assessment. They share the spine (one composition factory, model bound in CLI via ModelConfig.agentic, content-neutral processors over typed slots, project-loaded domain/"ontology" seam, fail-closed LLM-judge firewall, Kiro fresh-subagent steering). DocuHarnessX realizes "self-improving multi-agent" via the firewall + claude-code/opencode steering loop, NOT MetaAgent.evolve (Train is future there); OpenUltraSAST builds the evolve loop on the same substrate. Three principled divergences (hybrid runtime confining HarnessX to the hunter pool; evolve reward/feasibility split + ledger; zero-dep core with opt-in extra) with reconciliation, plus a concrete Phase 3 blueprint mirroring DocuHarnessX. Checks off spec task 5.1. Co-Authored-By: Claude Opus 4.8 <[email protected]>
8.2 KiB
DocuHarnessX ↔ OpenUltraSAST — Blueprint Alignment
How OpenUltraSAST's HarnessX integration (Phase 3+) aligns with DocuHarnessX
(/home/mc/Source/DocuHarnessX), the author's other HarnessX project. Both are HarnessX
bundles steered from claude-code/opencode via Kiro spec-driven development. Goal: one shared
architecture the steering layer drives identically.
Orientation
DocuHarnessX is agent-first — an 8-stage pipeline (ingest → analyze → classify → plan → write → review → assemble → deploy) that is the agent loop. OpenUltraSAST is a
deterministic-pipeline + agentic-plane hybrid — a sync HarnessRuntime driving 13 stages,
with HarnessX confined to the one stage that is genuinely an agent loop (the hunter pool). They
converge on the same load-bearing patterns and diverge only where SAST's determinism and
supply-chain posture require it.
What "self-improving multi-agent system" means in DocuHarnessX (important): it does not
use meta_harness / MetaAgent.evolve at all (the Train loop is explicit future / out of
scope). Its self-improvement is realized two ways: (1) an in-product fail-closed LLM-judge
quality firewall (COBESY: fixed criteria, threshold-re-derived verdicts, unavailable → fail),
and (2) the claude-code/opencode Kiro steering loop (fresh implementer → adversarial
reviewer → debugger subagents per task). OpenUltraSAST inherits both substrates and additionally
builds the MetaAgent.evolve loop DocuHarnessX leaves unbuilt.
Shared blueprint (the spine)
| Concern | DocuHarnessX | OpenUltraSAST | Verdict |
|---|---|---|---|
| Composition seam | make_docgen in docuharnessx/bundle.py — the only HarnessX import site; control | stages_builder(); returns model-less HarnessConfig |
build_sast() in harness/build_sast.py (mirrors examples/coding/build_coding), lazy behind _has_harnessx() |
shared |
| Model binding | CLI prepare_run(): model_config.agentic(make_docgen(...)); model on harness.model_config.main, never in config |
HxScanOrchestrator: asyncio.run(model_config.agentic(cfg).run(ScanTask(...))) |
shared |
| Processor base | NoOpStage(MultiHookProcessor), content-neutral on step_end, real module-level classes for _target_ resolution |
MultiHookProcessor(skip_model=True) + SlotContractMixin, real module-level classes |
shared |
| Inter-stage seam | RunContext over append-only slot constants; frozen versioned handoff dataclasses |
typed sast.* slots + SlotContractMixin (reads_slots/writes_slots) |
shared |
| Domain / "ontology" seam | .docuharnessx/ontology.yaml → Vocabulary (Role×Subject×Intent), loaded at run start |
central CWE policy + ruleset (policy/CWE_Score.tsv + ruleset/*.toml + rule_policy.json), loaded at run start |
analogous |
| Acceptance firewall | COBESY all-of gate; judge passed untrusted/re-derived; unavailable → fail |
VerifyProcessor (llm-judge + structural fallback, rejects unknown reachability, fail-closed) |
analogous |
| Steering | Kiro SDD; CLAUDE.md; .kiro/{steering,specs}; kiro-impl fresh-subagent + adversarial review; kiro-verify-completion |
same Kiro convention; .kiro/specs/harnessx-self-improving-rulesets/*; OpenCode steers, kiro-* maintainer-only |
shared |
Self-improvement (evolve) |
none — future seam | improve/evolve.py → MetaAgent.evolve, bounded rule/policy levers, rule_policy.json ledger |
diverges (OUS builds it) |
| Dependency posture | harnessx direct git dep + pyyaml |
core zero-dep; harnessx optional SHA-pinned extra, lazy |
diverges (by design) |
Three principled divergences (and reconciliation)
- Agent-first vs hybrid. OUS keeps the sync
HarnessRuntimethrough Phases 0–4 and confines HarnessX to the hunter pool (the runtimes are "incompatible at every load-bearing point — bridge, do not map"). Reconcile by treatingbuild_sast()as building only the hunter sub-harness, applying DocuHarnessX'smake_docgenpattern at the hunter-pool boundary. Optional Phase 5 converges OUS toward DocuHarnessX's agent-first end-state (retireHarnessRuntime) — the divergence is temporal, and DocuHarnessX is the north star. - Editable ontology vs authoritative severity. DocuHarnessX's whole vocabulary is editable
presets. OUS splits its domain seam into a mutable detection vocabulary (
ruleset/*.toml, loop- and human-editable) and an immutable severity/scope authority (CWE_Score.tsv, verycode-upstream, the loop must never edit). Where DocuHarnessX relies on convention ("never a hardcoded literal"), OUS relies on a validator (EvolveValidator._policyforbids editing the 0–5 severity) because a loop, not just a human, edits it. - Firewall-as-reward vs reward/feasibility split. DocuHarnessX's firewall is the signal
(binary pass/fail). OUS must feed
MetaAgent.evolve, so it keeps a scalar reward (project_score) separate from a hard feasibility constraint (≥90% recall / <10% FP), un-folded so the loop can't game the number. Reuse DocuHarnessX's fail-closed firewall verbatim at the per-findingVerifyProcessorgranularity; layer the reward/feasibility split on top.
Phase 3 blueprint for OpenUltraSAST (mirror DocuHarnessX)
build_sast()factory = the single HarnessX composition import site (DocuHarnessX's "blast radius is this file" rule onbundle.py);control | hunter_stages_builder(); raised loop thresholds (large-repo scanning revisits shapes, like large-repo docs); model bound later inHxScanOrchestrator. OUS delta: the_has_harnessx()guard + raise-then-fallback torun_hunter_pool().- Ontology seam = CWE policy + ruleset as OUS's "ontology":
load_ruleset(path, ledger)+load_policy(tsv)loaded intosast.*slots at run start;resolve_severity()is the single severity authority (mirrors DocuHarnessX's "every transform reads the loaded store, never a literal"); absent ledger → byte-identical baseline; unmapped enabled-rule CWE → fail-loud (stricter than DocuHarnessX, because severity is authoritative). - Processor set: register HarnessX classes directly only inside the hunter sub-harness
(LoopDetection, CostGuard/TokenBudget, ToolFailureGuard, ToolFilter, SelfVerify, EpisodeMetrics/
OTel/Checkpoint); everything deterministic is a
skip_model=TrueMultiHookProcessorover slots (SarifIngest/Preprocess/EntryPoint/Rank/Calibrate/QuickFindings/PolicyScoring/Verify/Score) with stablemake_<stage>_processor()factories so a spec replaces exactly one stub in place. MetaAgent.evolveloop (Phase 4, on the same substrate): two bounded levers (rule,policy); reward =project_score; feasibility = recall/FP gate (un-folded); signal path benchmark per-rule precision/recall +rule_policy_delta→rule_signals.json→MetaAgent.evolve; gate = validity (canonicalize → contract →_rules/_policy→ replay) → novelty/evidence → re-benchmark → attribution → accept or byte-for-byte revert (the structural analog of DocuHarnessX'sDEFAULT_UNAVAILABLE_VERDICT="fail"); ledger =rule_policy.json(OUS's resume-safe analog of DocuHarnessX's markdown round journal).- Steering surface: reuse DocuHarnessX's
kiro-*skills verbatim (maintainer-only); add SAST-domain.kiro/steering/rules pinning the detection gate as a hard invariant, the zero-dep guard, and thepip --dry-runaudit gate; traceable per-module docstrings citing spec Req/Decision numbers.
Net
The two projects already share the spine — one composition factory, model bound in the CLI via
ModelConfig.agentic, content-neutral processors over typed slots, a project-loaded domain seam,
a fail-closed acceptance firewall, and the Kiro fresh-subagent steering loop. OpenUltraSAST diverges
in exactly three principled places (hybrid runtime confining HarnessX to the hunter pool; it builds
the MetaAgent.evolve loop with a reward/feasibility split + rule_policy.json ledger; zero-dep core
with HarnessX opt-in). Adopting DocuHarnessX's load-bearing patterns at the points above gives the
two projects one architecture that opencode/claude-code steers identically.