Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 0 additions & 5 deletions .github/actions/prune-repository/prune.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,6 @@
# The app's condition-5 test executes the evaluation runner as a child
# process; the context root is not a workspace and must be copied explicitly.
"@apps/brunch-agent": ["libs/@hashintel/brunch-agent/evaluations"],
# Repertoire tests read sibling plugin.yaml files by relative URL.
"@hashintel/brunch-agent-repertoire": [
"libs/@hashintel/brunch-agent/packages/plugin-sdcpn/plugin.yaml",
"libs/@hashintel/brunch-agent/packages/plugin-gherkin/plugin.yaml",
],
}

TURBO_QUERY = """
Expand Down
10 changes: 0 additions & 10 deletions .github/actions/prune-repository/prune_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
TRANSPORT = "@hashintel/brunch-agent-transport-aisdk"
APP = "@apps/brunch-agent"
WEBSITE = "@apps/petrinaut-website"
REPERTOIRE = "@hashintel/brunch-agent-repertoire"


class BrunchRequestedExtras(unittest.TestCase):
Expand Down Expand Up @@ -47,15 +46,6 @@ def test_app_job_adds_the_baseline_evaluation_paths(self) -> None:
["libs/@hashintel/brunch-agent/evaluations"],
)

def test_repertoire_job_copies_sibling_plugin_yaml(self) -> None:
self.assertEqual(
extra_paths_for_requested({REPERTOIRE}),
[
"libs/@hashintel/brunch-agent/packages/plugin-sdcpn/plugin.yaml",
"libs/@hashintel/brunch-agent/packages/plugin-gherkin/plugin.yaml",
],
)

def test_sibling_or_website_job_does_not_add_brunch_extras(self) -> None:
self.assertEqual(extras_for_requested({TRANSPORT}), frozenset())
self.assertEqual(extras_for_requested({WEBSITE}), frozenset())
Expand Down
5 changes: 2 additions & 3 deletions libs/@hashintel/brunch-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ This directory is its context and agent-session root, not a package workspace:
- [`docs/INDEX.md`](./docs/INDEX.md) indexes Brunch documentation.
- [`docs/control/STEERING.md`](./docs/control/STEERING.md) holds current strategic truth;
[`STRATEGY-LOG.md`](./docs/control/STRATEGY-LOG.md) records material strategic decisions.
- [`packages/core/`](./packages/core/) is `@hashintel/brunch-agent`.
- [`packages/core/`](./packages/core/) is `@hashintel/brunch-agent`; its guarded `./prompts`
subpath ships the harness repertoire rendered by bindings and never imported by plugins.
- [`packages/binding-flue/`](./packages/binding-flue/) is the Flue binding.
- [`packages/transport-aisdk/`](./packages/transport-aisdk/) is the AI SDK transport.
- [`packages/repertoire/`](./packages/repertoire/) is the harness repertoire: the default teaching
for every guidance and runbook key (ADR-0007), rendered by bindings, never imported by plugins.
- [`packages/plugin-gherkin/`](./packages/plugin-gherkin/) is the Gherkin target plugin: a
feature-anchored `plugin.yaml` and the verbatim-floor proposal type.
- [`packages/plugin-sdcpn/`](./packages/plugin-sdcpn/) is the SDCPN target plugin: an
Expand Down
1 change: 1 addition & 0 deletions libs/@hashintel/brunch-agent/docs/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ contract requires the spec to carry the new operating truth, in explicitly dated
| [0005-model-assisted-sdcpn-realization](adr/0005-model-assisted-sdcpn-realization.md) | accepted | FE-1480 | A pure plugin projection emits an SDCPN scaffold, typed code-obligation sidecar, and loss report; the Brunch agent realizes executable TypeScript through Petrinaut client tools and deterministic compile/simulation gates |
| [0006-plugins-per-target-formalism](adr/0006-plugins-per-target-formalism.md) | accepted | design-convergence review 2026-08-25 | Plugins are per target formalism, authored as sectioned Markdown with fixed contract headings and three machine-read tables; domain-neutral by rule; retires the declarative ScopeExpr/firesWhen/DemandTable contract |
| [0007-harness-teaching-meets-plugin-content-at-fixed-keys](adr/0007-harness-teaching-meets-plugin-content-at-fixed-keys.md) | accepted | FE-1406 (owner), FE-1431, FE-1393; accepted 2026-08-25, key catalogue converging (decision 9) | Plugin authoring is a fixed set of harness-owned keys in four groups — contract data (`ontology`, `schema`, `patterns`), guidance typed by mechanism (`lenses`, `techniques`, `movements`, `licenses`, `motifs`, `smells`, `rabbit_holes`, `failure_modes`), per-job runbooks (`kickoff`, `trajectory`, `close`), machinery (`checks`, `tools`) — each rendered key → harness default → plugin cell; the repertoire is `packages/repertoire`; amends ADR-0006 decisions 2 and 5 |
| [0008-repertoire-and-plugin-contract-live-in-core](adr/0008-repertoire-and-plugin-contract-live-in-core.md) | accepted | FE-1507; accepted 2026-08-26 | The repertoire is core-owned prompt data behind `@hashintel/brunch-agent/prompts`; plugins must not import that subpath; the standalone repertoire workspace is removed; amends ADR-0007 decision 8 |

## External canonical documents

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# ADR-0008: Repertoire and plugin contract live in core

Date: 2026-08-26
Status: accepted 2026-08-26 (Lu)
Amends: [ADR-0007](0007-harness-teaching-meets-plugin-content-at-fixed-keys.md),
decision 8 (`packages/repertoire` is replaced by a guarded core subpath)
Preserves: ADR-0007 decisions 1–7 and 9; the repertoire remains harness-owned,
plugins fill cells without importing it, and the catalogue still converges by
co-authoring
Decided on: the `ln/w4-topology` branch, from the package-direction audit
commissioned by [S-011](../control/STRATEGY-LOG.md#s-011)

## Context

ADR-0007 gave the harness's default teaching a package so the concept had an
executable owner rather than another prose-only home. The implementation proved
that ownership, but the package boundary is not carrying an independent
architectural role.

The key catalogue, Valibot plugin-definition schema, emitted JSON Schema,
repertoire schema and reader, and instruction renderer all live in
`@hashintel/brunch-agent`. The separate
`@hashintel/brunch-agent-repertoire` workspace contains one YAML document and a
one-line load through core's `readRepertoire`. It has no runtime, deployment,
versioning, or consumer boundary of its own. A Flue binding and the baseline
evaluation import it only to obtain the harness's default prompt data.

Keeping that workspace makes a core concern look like a peer package and adds
manifest, build, lint, test, and dependency wiring without strengthening the
rule that matters: plugins must not import the repertoire. Moving the default
onto core's root export would remove the workspace but weaken that rule in the
other direction. Core's root is the plugin SDK, so every plugin is allowed to
import it; a root-exported repertoire would make the forbidden dependency
architecturally ordinary.

## Decision

1. **The repertoire is core-owned prompt data.** Remove the
`@hashintel/brunch-agent-repertoire` workspace. Its default content and
module-load validation move into `@hashintel/brunch-agent`.

2. **Default teaching has a guarded subpath.** Core exports the loaded default
as `@hashintel/brunch-agent/prompts`. Bindings and evaluation composition may
import that subpath. Plugin packages may not import it. The root
`@hashintel/brunch-agent` export remains the plugin SDK and harness
mechanism; it does not export the default repertoire.

3. **The plugin contract already belongs to core.** The key catalogue,
`PluginDefinitionSchema`, readers, repertoire shape, emitted
`schema/plugin.schema.json`, and schema changelog stay in core. This decision
creates no schema package and no public `schemas` subpath.

4. **Package ownership is the whole decision.** This record does not reorganise
core into `loop/`, `prompts/`, `schemas/`, or `skills/` directories. Those
names remain possible internal roles, not accepted folders. A later move
needs concrete pressure from the files it would separate rather than this
package correction as a pretext.

5. **The direction is executable.** The architecture suite must fail while the
standalone repertoire workspace exists, require the `./prompts` core export,
and reject a plugin source import of that subpath. It continues to require
plugins to resolve core only and core to import no substrate.

## Rejected alternatives

- **Keep the repertoire workspace.** Rejected because the package contains data
plus a thin loader around types and behavior already owned by core. It
encodes no independently useful boundary.
- **Export the repertoire from core's root.** Rejected because the root is the
plugin SDK. Plugins could then import harness defaults through their one
permitted dependency, making ADR-0007's ownership direction invisible to the
package graph.
- **Restructure all of core now.** Rejected because the package audit proves one
boundary is premature; it does not prove the flat internal modules have
become hard to navigate or need four new directory boundaries.

## Consequences

- Bindings and the baseline evaluation replace their repertoire-package import
with `@hashintel/brunch-agent/prompts`; plugin imports remain unchanged.
- The repertoire workspace, its manifest and workspace dependency edges are
removed in one mechanical move. The key catalogue and its changelog do not
move.
- That move reconciles the package topology in the elicitation-kernel spec and
its living topology reference. The driver reconciles `CONTEXT.md` and
`docs/INDEX.md` when the lines rejoin; until then this record owns the
accepted shape where those files still name `packages/repertoire`.
- The plugin co-authoring stream keeps the current layout until this decision
is accepted, then takes the mechanical move between cycles; the move changes
no key or repertoire text.
- Removing a workspace is not proof by itself. The import-direction
architecture test is red on the old topology and green only when the guarded
subpath and plugin prohibition both hold.
12 changes: 6 additions & 6 deletions libs/@hashintel/brunch-agent/docs/control/STEERING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ evidence under [proof evidence](../evidence/proofs/).
- [ADR-0007](../adr/0007-harness-teaching-meets-plugin-content-at-fixed-keys.md) — harness-owned
fixed keys join defaults to plugin cells; operative force: cycle two froze the catalogue, which
reopens only when run evidence forces a key change, while FE-1393 tests gherkin generality.
- ADR-0008 — repertoire defaults are core-owned prompt data behind a guarded
subpath; operative force: plugins never import
- [ADR-0008](../adr/0008-repertoire-and-plugin-contract-live-in-core.md) — repertoire defaults are
core-owned prompt data behind a guarded subpath; operative force: plugins never import
`@hashintel/brunch-agent/prompts`, the root remains the plugin SDK, and no broader core
reorganisation follows from this package correction.
- [S-001](STRATEGY-LOG.md#s-001) — review-and-revise is the current proof, not permanent scope;
Expand Down Expand Up @@ -114,7 +114,7 @@ evidence under [proof evidence](../evidence/proofs/).
FE-1431 (plugin authoring surface).
- **Harness teaching has one owner** — repertoire defaults fill every guidance and runbook key;
operative force: plugins specialize those keys without importing harness method. Source:
ADR-0008 and
[ADR-0008](../adr/0008-repertoire-and-plugin-contract-live-in-core.md) and
[S-008](STRATEGY-LOG.md#s-008). Steering projection:
FE-1406 (harness repertoire).
- **A second formalism tests generality after the tracer** — gherkin pressures the settled SDCPN
Expand Down Expand Up @@ -239,9 +239,9 @@ Re-braid (restack and resolve, then diverge again). Length follows how fine the

| Triangle edge | Today | Gap |
| --- | --- | --- |
| **Panel → Brunch** | W1 routes the real panel's `/api/chat` to the SDCPN elicitor; `yarn dev:brunch` starts both services; `brunch_ask` round-trips. | Re-braid W1 with W2, then conduct the human Proof 0 run. |
| **Panel → Brunch** | W1 routes the real panel's `/api/chat` to the SDCPN elicitor; `yarn dev:brunch` starts both services; `brunch_ask` round-trips. | Conduct the human Proof 0 run from the re-braided `hash-timing` checkout. |
| **Persistence modelled** | W1 sends one stable ui-shell principal on every request, resolves it to one target document and namespaced sessions, and stamps an opaque owner key that refuses cross-principal reads and writes. SQLite and per-document JSON remain. | Witness reload against the re-braided live surface; no persistence design gap remains for G0. |
| **Real elicitation** | The production SDCPN elicitor is reachable from the panel on W1; captures, sweep outcomes, and completion are rendered readably, and the attach contract is recorded. | Re-braid timing onto the W1 line, then conduct the eight-turn human run with a screen recording and a plain-language account under proof evidence. |
| **Real elicitation** | The production SDCPN elicitor is reachable from the panel on W1; captures, sweep outcomes, and completion are rendered readably, and the attach contract is recorded. | Conduct the eight-turn human run from `hash-timing`, with a screen recording and a plain-language account under proof evidence. |
| **Deployment (G2)** | — | Was Linear-gated behind gherkin via FE-1423 ← FE-1396; that blocker was removed 2026-08-26. FE-1440/FE-1441 remain the owners. |

### Tool inventory — current truth and intent
Expand Down Expand Up @@ -408,7 +408,7 @@ changes the witness: latency is no longer a number in a transcript but a person
subpath, fixed keys, a schema, and gates — never as spec prose alone; its content is not rescoped
without run evidence ([S-008](STRATEGY-LOG.md#s-008),
[ADR-0007](../adr/0007-harness-teaching-meets-plugin-content-at-fixed-keys.md),
ADR-0008).
[ADR-0008](../adr/0008-repertoire-and-plugin-contract-live-in-core.md)).
- The key catalogue is a working set until a cycle changes no key: fix it by writing both plugins
against it, not by decree ([S-009](STRATEGY-LOG.md#s-009), ADR-0007 decision 9).
- The triangle first, poorly; no layer is optimised for its own sake before the end-to-end flow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ packages/core LANE 3 (harness; substrate-free)
├─ naming.ts ✓ identity/tool-name policy (ADR-0001)
├─ plugin.ts ✓ plugin identity + one declared proposal floor (FE-1392); grows the
│ full catalog/tables/ops contract at FE-1393
├─ prompts.ts,
│ repertoire.yaml ✓ guarded `./prompts` subpath: validated harness-default teaching;
│ binding/evaluation composition only, never a plugin import (ADR-0008)
├─ testing/ ✓ test utilities subpath (mirrors Flue's own store-contract pattern)
├─ ask-protocol.ts ✓ substrate-free ask/suspension mechanism: affordance minting, guard,
│ reply-binding signal, and instruction fragments (FE-1422). See N1.
Expand Down Expand Up @@ -83,13 +86,11 @@ evaluations/protocols/process-model-elicitation/baseline/run.ts EXPERIMENT PRO
refusal), prompt content, and advisory semantics;
`useElicitation` contributes only Flue projection, hooks, persistent-state, private-prompt,
refresh, and durable-step wiring. A future `binding-pi` reuses both protocol modules.
- **N2 (packs and cards).** Plugin-owned content lives in plugin packages, exported as
`defineSkill`-compatible definitions; the app's agent module _registers_ what the plugin
exports. Never per-agent `skills/` dirs holding plugin content in the app — that puts lane-3
policy inside lane-1, invisible to the boundary gates. Quiver (FE-1406) content is
harness-shipped: same rule, exported from core (or a `packages/quiver`), registered by hosts.
Card content stays assertable outside the Vite graph (fixture-grade copies; B4's probe
decides the exact shape).
- **N2 (plugin cells and the repertoire; amended by ADR-0007 and ADR-0008).** Plugin-owned content
lives in plugin packages; never in per-agent app `skills/` directories, which would put lane-3
policy inside lane-1 and outside the boundary gates. Harness-owned teaching lives in core and is
exported only from `@hashintel/brunch-agent/prompts`; bindings and evaluation composition may
import it, plugins may not. The committed YAML remains directly assertable outside the bundle.
- **N3 (application composition; amended by ADR-0004 / FE-1437).** There is no dedicated demo
shell. The standalone `apps/dev` was imported as `apps/brunch-agent`, which owns the remote
Brunch server, target gallery, and diagnostics. `apps/petrinaut-website` owns the user-facing
Expand Down
12 changes: 7 additions & 5 deletions libs/@hashintel/brunch-agent/docs/specs/elicitation-kernel.md
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,8 @@ Bun-workspace monorepo in this repo:

```text
packages/core # the harness; plugin SDK is its public export surface
packages/core/prompts # (subpath) the harness's default repertoire; binding/evaluation only
packages/core/testing # (subpath) fixtures, arbitraries, replay driver — prod bundles stay clean
packages/repertoire # the harness's own filling of every guidance and runbook key (ADR-0007); depends on core only
packages/binding-flue # the Flue binding (implements §10; owns the storage port impl)
packages/transport-aisdk # validated UI ingress + harness replies → AI SDK wire; no binding/substrate imports
packages/plugin-gherkin
Expand All @@ -648,12 +648,14 @@ it does not wrap or flatten these package boundaries.
a package-manager root: it carries no package manifest, lockfile, or competing toolchain.
`apps/brunch-agent` remains at HASH's application root and points back to that context authority.

**ADR-0007 amendment (2026-08-25):** `packages/repertoire` (`@hashintel/brunch-agent-repertoire`)
carries the harness's default teaching for every guidance and runbook key. It depends on `core`
only; bindings depend on it to render instructions; plugins never import it.
**ADR-0007 / ADR-0008 amendment (2026-08-26):** the guarded
`@hashintel/brunch-agent/prompts` subpath carries the harness's default teaching for every guidance
and runbook key. Bindings and evaluation composition may import it to render instructions; plugins
never import it. The root `@hashintel/brunch-agent` export remains the plugin SDK.

**Dependency invariants (spec invariants):** plugins depend on `core` only — never on the binding,
never on Flue; the harness imports no substrate; a binding imports both. A transport consumes
never on Flue, and never on the guarded `core/prompts` subpath; the harness imports no substrate; a
binding imports both. A transport consumes
harness-level reply parts plus its wire encoder and ingress validator only: `transport-aisdk`
depends on `core`, `ai`, and `valibot`, never on a binding or Flue. **Role prefixes name what a
package is architecturally**: plugin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ import {
projectFlueHistoryForSweep,
} from "@hashintel/brunch-agent-binding-flue";
import { sdcpn, sdcpnDefinition } from "@hashintel/brunch-agent-plugin-sdcpn";
import { repertoire } from "@hashintel/brunch-agent-repertoire";
import { repertoire } from "@hashintel/brunch-agent/prompts";
Comment thread
cursor[bot] marked this conversation as resolved.

import {
createTurnTimingRecorder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,8 @@
"message": "Brunch libraries must not depend on Petrinaut implementations."
},
{
"group": [
"@hashintel/brunch-agent-*",
"!@hashintel/brunch-agent-repertoire"
],
"message": "A binding may depend inward on the harness and render its repertoire, not depend on other Brunch extensions."
"group": ["@hashintel/brunch-agent-*"],
"message": "A binding may depend inward on the harness, not depend on other Brunch extensions."
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"@flue/runtime": "2.0.3",
"@flue/sdk": "2.0.3",
"@hashintel/brunch-agent": "workspace:*",
"@hashintel/brunch-agent-repertoire": "workspace:*",
"valibot": "1.4.2"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import {
type Plugin,
type SweepState,
} from "@hashintel/brunch-agent";
import { repertoire } from "@hashintel/brunch-agent-repertoire";
import { repertoire } from "@hashintel/brunch-agent/prompts";

import { capturedUserEntryIdsForSession } from "./capture-accounting";
import {
Expand Down
Loading
Loading