Skip to the content.

Typed harness asset composition

fak harness compose compiles the ordered layers emitted by contextual selection into one inert, provenance-bearing effective asset set:

fak harness select  ... > selection.json
fak harness compose --assets harness-assets.json --selection selection.json

The asset manifest schema is fak.harness-assets/v1alpha1. Its initial closed kinds are instruction, tool, memory, policy, route, secret, workflow, and ui. Each declaration carries layer/source identity and one explicit operation: add, replace, or remove.

Merge rules by kind

Kind Duplicate/add Replace Remove Additional floor
instruction identical retains; different conflicts explicit only allowed unless locked/mandatory ambiguous activation never silently wins
tool identical retains; different conflicts explicit only allowed unless locked/mandatory ambiguous tool implementation never silently wins
memory same namespace/boundary only explicit within same boundary allowed unless locked/mandatory project/domain/task memory boundary must equal owning layer
policy later declarations may add denies/remove grants widening refused allowed unless locked/mandatory an existing deny or absent parent grant cannot become a later grant
route identical retains; different conflicts explicit only allowed unless locked/mandatory route changes are visible replacements
secret identical reference retains refused allowed unless locked/mandatory opaque reference required; inline value forbidden
workflow identical retains; different conflicts explicit only allowed unless locked/mandatory mandatory witness/workflow cannot be removed
UI identical retains; different conflicts explicit only allowed unless locked/mandatory UI preference never gets policy semantics

Any kind can be locked by its source layer. A locked asset cannot be changed or removed by a narrower layer. Mandatory assets cannot be removed. Every effective asset names its source layer, and every action emits an add/retain/replace/remove/narrow trace.

This is deliberately not generic last-writer-wins. Instructions and tools require an explicit replacement when names collide. Memory cannot silently cross a project/domain/task boundary. Policy can become narrower but not wider. Secret references cannot be swapped by a lower layer, and raw secret values are invalid.

Witness and boundary

The mixed company/person/project/legal/task witness composes all eight kinds deterministically. The 8-kind × 3-operation matrix covers every kind with add, replace, and remove. Adversarial tests seed policy widening, secret replacement, mandatory witness removal, instruction/tool ambiguity, and memory cross-contamination; each fails before launch with the source layer, kind, and asset ID.

Selection order is consumed directly from selection.json; discovery and classification are not reimplemented. This leaf resolves typed overlap semantics from #6904. It does not yet solve version/dependency ranges, cycles, provider ambiguity, compatibility budgets, or lock digests; those remain the broader deterministic resolver #6792. It also emits inert assets rather than projecting into Codex/Claude/Copilot or launching pkg/harnesskit (#6901).