Skip to content

docs(architecture): ADR set for agent-driven Frigg development#592

Draft
seanspeaks wants to merge 12 commits into
nextfrom
claude/frigg-integration-overhaul-57VHW
Draft

docs(architecture): ADR set for agent-driven Frigg development#592
seanspeaks wants to merge 12 commits into
nextfrom
claude/frigg-integration-overhaul-57VHW

Conversation

@seanspeaks

@seanspeaks seanspeaks commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds five cross-referenced ADRs proposing the architecture for agent-driven Frigg integration work. Each is dependent on the prior; intended to land together as one decision unit. Implementation is intentionally not in this PR — these are decision artifacts.

Four are forward-looking proposals. One — ADR-EXTENSIONS — has had its Tier 3 section reconciled to ratify what Daniel already shipped on next in PR #590 + PR #596; the other tiers in that ADR remain proposed.

  • ADR-INTEGRATION-CAPABILITIES — Structured static Definition.capabilities declaration on integration classes with pointer discipline (capability surface, primitive, backedBy, implementedBy). Replaces ad-hoc "what does this integration do" knowledge with a typed graph.
  • ADR-ONTOLOGY-LAYERS — Four-layer ontology (L1 universal / L2 framework / L3 vendor-domain / L4 instance) compiled by @friggframework/ontology into XML-tagged context blocks. Includes module-exported ontology (each api module ships its own L3 fragment), multi-source compilation, validation subagent pattern, and the friction-capture loop adopted from Freya as a shared @freyaframework/friction package.
  • ADR-AGENT-HARNESS@friggframework/harness package wiring the capability resolver + ontology compiler into Claude Code's SessionStart and SubagentStart hooks. Lifecycle taxonomy borrowed from Freya ADR-008 maps Frigg's touchpoints onto the 9-phase agent lifecycle; decorator-vs-hook framing for separating port-wrapping concerns from loop-punctuating concerns.
  • ADR-EXTENSIONS — Three-tier pluggable-code taxonomy (Tier 1 Core Plugins, Tier 2 Application Extensions, Tier 3 Integration Extensions) plus Artifacts and the Capability Declaration as sibling concepts. Status is mixed: Tier 3 Integration Extensions is Implemented (PR #590 + PR #596; the Tier 3 section in this ADR was reconciled to match what shipped — namespaced routes under binding key, useDatabase resolution, fail-loud defaults). Tier 1, Tier 2, Artifacts, and the Capability Declaration remain Proposed. Quick-start for shipped Tier 3 lives at packages/core/integrations/EXTENSIONS.md.
  • ADR-EVALS — Eight-condition matrix measuring whether capabilities + ontology + harness actually lift task accuracy; pre-registered falsification criteria. The cheap upstream precursor that decides whether ADR-EVALS' full matrix is worth building lives at lefthookhq/lefthook--dev-toolkit:evals/PLAN.md — three-arm ablation (Raw / Skill / Skill+Ontology+Validation+Friction) × two pilot tasks (one sync, one non-sync) × three replications, with hypothesis section and per-arm score predictions.

Test plan

  • Read the five ADRs in order: EXTENSIONS → INTEGRATION-CAPABILITIES → ONTOLOGY-LAYERS → AGENT-HARNESS → EVALS
  • Verify cross-references resolve and the dependency story is coherent
  • For ADR-EXTENSIONS specifically: confirm the Tier 3 section accurately reflects shipped behavior — URL pattern /api/{integration}-integration/{bindingKey}{route.path}, useDatabase resolution order, event-vs-route namespacing asymmetry, fail-loud defaults including the boolean-validation throw added in feat(core,devtools): namespace extension routes + useDatabase flag #596
  • Resolve open questions inline (each ADR has 6–10 explicit open questions; ~12 substantive decisions still pending across the set)
  • Confirm the Freya-borrowed friction pipeline shape aligns with what the shared @freyaframework/friction package will actually ship

Open follow-ups not covered here

  • @freyaframework/friction shared package — confirm trimmed v1 surface with Freya ADR-009 roadmap (cross-framework alignment, not Frigg-internal)
  • Tier 1 (Core Plugins) and Tier 2 (Application Extensions) implementations in next once their Proposed sections settle
  • Artifacts and Capability Declaration implementations
  • Precursor eval execution on lefthookhq/lefthook--dev-toolkit once these decisions settle (skill copy + judge calibration + 18 runs)

Notes

  • Opened as Draft — proposed status, open questions remain. Move to ready-for-review once decisions are settled.
  • No release / prerelease labels — this PR ships only docs. Add labels when promoting beyond ADR proposal stage.
  • ADR-EXTENSIONS Tier 3 section is the one place in this PR that ratifies shipped reality rather than proposing forward; it's the same posture every other framework uses for ADRs covering already-implemented mechanisms (decision-of-record after the fact).

Generated by Claude Code

seanspeaks and others added 12 commits May 22, 2026 14:36
Defines a three-tier model for what's pluggable in Frigg, distinguishing
Core Plugins (required infrastructure with defaults — provider, queue,
encryption), Application Extensions (optional cross-cutting features on
appDefinition.extensions), and Integration Extensions (off-the-shelf
handler bundles on IntegrationBase.Definition.extensions).

Grounds the model in existing prototypes: the packages/core/extensions
system on claude/frigg-netlify-exploration-aY2Bh for Tier 2, and the
this.extensions pattern in the frigg-2.0 downstream repos for Tier 3.
Calls out current shape mismatches (array vs object, constructor vs
static Definition, vocabulary collision) and proposes resolutions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Builds on the three-tier plugins/extensions taxonomy on adr/extensions.
Adds two sibling concepts that surfaced in the integration-overhaul
design conversation:

Artifacts — code or configuration the API module helps the developer
generate (often via a vendor CLI like `hs project add` or `slack
scaffold`) that runs outside Frigg on the target platform. Deliberately
not a fourth tier: the three tiers describe pluggable code inside the
Frigg runtime; Artifacts run outside it. Required (`base`) or optional
per artifact. Lives on `apiModule.Definition.artifacts`.

API Module Capability Declaration — a structured `capabilities` block
that answers "what can I do with this API module?" Each capability is
backed by a spec (OpenAPI/AsyncAPI/Arazzo/Fenestra) and implementedBy
one of three mechanisms: the API class (atomic ops), a Tier 3 Integration
Extension (Frigg-side composition), or an Artifact (extra-Frigg code).
JSON-Schema-validatable; mirrors Fenestra's modular schema conventions.

Also: refreshed comparison table to include Artifacts as a fourth column,
added Phases 5 and 6 (Capability Declaration schema, Artifacts tooling),
added Open Questions 5-8 (binding validation, vendor CLIs, capability-
type set boundaries, defaultConfig.json scope), and extended references
with the spec families and the Fenestra draft location.

No code changes; documentation only. Phase 1-4 from the original ADR
remain unchanged.
References Daniel Klotz's PR #590 (Tier 3 framework implementation) as the
in-flight realization of Phase 2. Closes gaps the prior revision flagged:

- **Framework load mechanism** subsection under Tier 3 documents the
  actual two-seam split #590 implemented — boot-time route claiming in
  integration-defined-routers.js, per-instance event merging via
  IntegrationBase._mergeExtensions() called from initialize(). Quotes
  the resolution-priority cascade, fail-loud conflict policy, and the
  two newly-added instantiation hooks (loadRouterFromObject's
  per-request closure and createQueueWorker's dry-instance branch).

- **Deferred from the initial implementation** subsection captures the
  three Phase-2 items #590 explicitly defers (per-class merge cache,
  worker-side getExtensionWorkers consumption, declarative route
  middleware seam) plus the pre-existing IntegrationBase DI gap that
  extensions now inherit.

- **Beyond { routes, events, queues, workers } — extending the contract**
  subsection enumerates primitives not yet in the extension contract:
  crons/schedules, user actions, config options, dynamic options. Calls
  out crons and user actions as highest-leverage v1.1 adds.

- **Core / API module boundary — worked example** subsection uses #590's
  findIntegrationByPortalId as a concrete teaching case for the
  platform-neutral-primitive-in-core vs platform-vocabulary-wrapper-in-
  extension rule. Cross-references the comment posted on #590 proposing
  the rename to findIntegrationByEntityExternalId.

Also: extends Phase 2 to reference #590's actual scope, adds Phase 7
for v1.1 contract extensions, adds Open Questions 9-14 (merge cache,
worker consumption, route middleware, IntegrationBase DI, contract
extensions, boundary-as-guideline), updates References with a new
"Framework implementation (in flight)" section pointing at #590.

No code changes; documentation only.
Proposes an integration-level Capability Declaration on
IntegrationBase.Definition.capabilities, extending the API-module-level
pattern from ADR-EXTENSIONS to the integration class. Capabilities are
descriptive (not generative), use the same backedBy + implementedBy
vocabulary as ADR-EXTENSIONS, and resolve via prototype chain with
inherits/override semantics.

Key additions specific to the integration layer:
- Primitive taxonomy (dataSync, workflow, userAction, configOption,
  lifecycleHook, webhookHandler, fenestraComponent, cron, aiInference,
  apiProxy, mcpTool)
- `surface` field on implementedBy (default / vendor-webhook /
  vendor-frontend / admin / internal) with auth model + route shape
  per surface
- Surface-selection rule: prefer default-surface primitives
  (getConfigOptions, USER_ACTION events, /api/v2/integrations) over
  declaring new routes; vendor-namespaced surfaces reserved for cases
  where the external system literally cannot reach default
- Pointer discipline — declarations point at code by name, never claim
  behavior

Includes a worked PipedriveIntegration example showing 8 current routes
collapsing to 2 own capabilities + 11 inherited (5 from BaseCRMIntegration,
6 from IntegrationBase).

Status: PROPOSED. Draft committed to preserve work-in-progress on the
overhaul branch while adversarial review is in flight. Known issues being
addressed in the next revision:
- Static validation of `implementedBy.events` requires either a static
  EventDefinitions field or admission that the lint is dynamic
  (this.events is constructor-wired today)
- `implementedBy.extensions` cross-reference needs to pin to local
  binding keys, not extension class names
- Multi-`via` capabilities need per-field discrimination (artifact
  surface vs Frigg-side backend)
- `surface: vendor-frontend` discriminator should likely reframe around
  credential carrier (Bearer / vendor-JWT / vendor-signature / none)
  rather than "where the UI runs"
- Companion ADRs (ontology-layers, agent-harness, evals) not yet drafted

Not yet ready for merge or PR to next.

https://claude.ai/code/session_01Wbyh477BTZHfMLQMzASnuc
…rial review

Four parallel reviewers (architectural coherence, Frigg API alignment,
agent-eval value, migration & drift) surfaced enough factual and
design errors that the draft needed a substantial rewrite.

Major corrections:

- Replace single `consumedBy` with `surface` + `auth` split.
  Surface describes where the endpoint is mounted (default,
  vendor-webhook, vendor-namespaced, admin, internal, mcp); auth
  describes which credential carriers it accepts (bearer, adopter-jwt,
  shared-secret, admin-key, vendor-signature, vendor-jwt, none). The
  earlier single-dimension framing collapsed surface and auth and led
  to the hand-wavy "vendor-frontend" enum value (now dropped).

- Fix all `/api/v2/...` references to actual current v1 paths.
  ADR-006 marks Phase 1-4 as accepted but no v2 router exists in the
  current checkout. Worked examples now cite the real v1 endpoints
  (`PATCH /api/integrations/:integrationId`, `/api/integrations/:id
  /actions/:actionId`, etc.).

- Replace references to `loadUser` / `requireLoggedInUser` /
  `requireAdmin` middleware. Those files live on
  `feature/integration-router-v2-drop-modules-router`, not on this
  branch. Actual current code uses inline `authenticateUser.execute()`
  inside handlers (packages/core/user/use-cases/authenticate-user.js
  :49-99), supporting four user-context auth methods, not one.

- Rebuild the Pipedrive worked example from the actual current
  four-route state (not the eight-route fiction from stale search
  results). Only `/uninstall` survives as a route after the cleanup
  per the May 25 #dev-feed thread; `callActivityDestination` and
  the admin script ride default-surface primitives with no new
  routes. Three own capabilities total; one route remaining.

- Split Phase 2 into Phase 2 (framework-only, IntegrationBase
  declaration) and Phase 2.5 (adopter base classes such as
  BaseCRMIntegration and BaseOutboundIntegration, which live in
  adopter repos and are not framework deliverables).

- Address the static-check viability gap. `this.events` is wired in
  constructors, so `validateCapabilityImplementation` cannot be
  purely static today. Propose a `static EventDefinitions`
  convention as a paired framework change; mark as Open Question 1.

- Pin `implementedBy.extensions` cross-references to binding keys
  (the locally-unique identifier in Definition.extensions),
  resolving the ambiguity flagged in architectural review.

- Drop multi-`via` as the default pattern. A capability with both
  Artifact and Frigg-side handler splits into sibling capabilities.
  Multi-via is now Open Question 4.

- Constrain `description` to purpose-not-behavior. Every worked-
  example description rewritten. Behavior claims are forbidden in
  the Definition — that's the pointer discipline.

- Add `extend` (array append) and `disinherit` to inheritance
  semantics. The earlier shape only supported `override` (shallow
  replace), which the architectural reviewer flagged as forcing
  authors to redeclare unchanged sibling fields when they only
  meant to add.

- Gate Phase 2 on PR #590 merged + one prerelease cycle stable.
  Gate Phase 5 on eval falsification criteria from ADR-EVALS
  (capability-only condition <8pp lift at Sonnet OR Haiku <70% at
  all-three-enabled triggers reconsideration).

- Add Revision history section documenting what changed and why,
  with provenance back to the four review findings.

Open Questions 5, 6, 9, 10 added; 1-4 and 7-8 updated to reflect
the corrected design.

The shape of the design (capability array, primitive + backedBy +
implementedBy, pointer discipline, inheritance via prototype chain)
survives. The factual layer that referenced auth middleware, v2
paths, and an eight-route Pipedrive was wrong; this revision
corrects it.

Not yet PR-ready. Three companion ADRs (ontology, harness, evals)
remain to draft.
Companion to ADR-INTEGRATION-CAPABILITIES. Defines the four-layer
ontology model (L1 universal non-obvious / L2 Frigg-context reading
discipline / L3 vendor and domain / L4 live-read instance) and the
in-house Node compiler that renders task-scoped subsets into
XML-tagged context blocks.

Key design decisions captured:

- Layer model stratifies by scope-of-applicability, not subject
  matter. More-specific layers override less-specific; locked
  constraints accumulate and survive overrides.

- Authoring discipline: imperative-verb constraints; pointer-only
  references to live code via retrieve_from; no behavioral facts
  about code in the ontology (behavior is the property of code,
  surfaced live).

- Node-based compiler shipped as @friggframework/ontology from the
  same monorepo. ~300 LOC core. CLI plus SDK. git+https URLs for
  remote ontology roots with version pinning at task start.

- Session protocol: pin ontology version at task start, never
  refresh mid-task. Refresh happens at task boundaries.
  Patch/minor bumps auto-adopt; major bumps (locked-rule changes)
  surface for review via ontology diff.

- Composition with ADR-INTEGRATION-CAPABILITIES is explicit and
  non-overlapping: capabilities answer what an integration DOES;
  ontology layers answer what an agent NEEDS TO KNOW to work on
  it. L4 entries are mostly pointers to capability declarations;
  the ontology teaches the agent how to find them, not what they
  say.

- L2 captures the surface-selection rule that surfaced in the
  May 24-25 dev-feed thread on Pipedrive routes. That rule was
  previously implicit institutional knowledge with no home.

- Adopter-portable: framework ships L1 + L2; adopter repos extend
  with L3 (vendor backstory) and L4 (instance pointers).

Phases land sequentially: schema + validator -> compiler -> drift
tooling -> seed framework L1+L2 -> adopter L3 -> harness wiring
(ADR-AGENT-HARNESS) -> eval measurement (ADR-EVALS).

Eight open questions captured; falsification criteria deferred to
ADR-EVALS.

Not yet PR-ready. ADR-AGENT-HARNESS and ADR-EVALS remain to draft;
fourth adversarial reviewer (agent-eval value) still in flight.
Wires ADR-INTEGRATION-CAPABILITIES and ADR-ONTOLOGY-LAYERS into a
Claude Code SessionStart hook plus an MCP server fallback.

The harness has three responsibilities:

1. Session-start injection. Reads the repo's harness config, runs
   resolveCapabilities(IntegrationClass) and compileContext(), and
   emits a single <FRIGG-HARNESS-CONTEXT> block with <ONTOLOGY> and
   <CAPABILITIES> sub-blocks for Claude Code to prepend as a system-
   prompt overlay.

2. Task pinning. First run for a new task writes .frigg-harness/
   state.json with the resolved ontology version + capability class
   hash + compiled block hash. Subsequent runs (including subagent
   invocations) reuse the pinned state. Mid-task drift is impossible
   by construction; default hash-mismatch policy is warn-and-recompile
   with stricter / laxer modes available.

3. Subagent propagation. spawnSubagentPrompt() helper templates the
   parent's pinned context into child prompts. A phase-executor
   subagent inherits the orchestrator's pinned ontology and
   capability versions; it never re-pins.

Optional fourth responsibility: MCP server fallback exposing the
same content via mcp__frigg-harness__get_capabilities(),
get_ontology(), pin_task(), resolve_pointer() tool calls. Same
content, pull-based instead of push-based, for agents outside Claude
Code's SessionStart-hook contract.

Active-integration detection is heuristic (auto-from-branch, auto-
from-cwd, explicit override). Failure modes default to graceful
degradation: missing config, unreachable ontology root, broken
capability declaration all warn-and-proceed rather than block. The
exception is locked-content budget overflow, which is a hard error
because locked constraints cannot be elided.

Two transports (SessionStart push vs MCP pull) ship together. The
eval (ADR-EVALS) measures which produces better task accuracy at
each model capability tier. The harness on/off is one of three
independent variables in the eight-condition matrix.

Phases land sequentially: package skeleton -> SessionStart hook ->
task pinning -> subagent propagation -> MCP fallback -> failure-mode
tests -> eval integration. Gates: Phase 2 of this ADR depends on
the resolver from ADR-INTEGRATION-CAPABILITIES and the compiler
from ADR-ONTOLOGY-LAYERS both shipping first.

Eight open questions captured; relationship to the eval ADR's
falsification criteria is forward-referenced.

Not yet PR-ready. ADR-EVALS remains to draft; fourth adversarial
reviewer (agent-eval value) still in flight.
Completes the four-ADR set. Defines the eight-condition factorial
matrix that tests the three independent variables (capability
declaration, ontology layers, agent harness) against a five-model
ladder spanning Haiku-class through Opus-class plus cross-vendor
and open-weights.

Falsifiable hypothesis with six explicit criteria gating Phase 5
of ADR-INTEGRATION-CAPABILITIES (rolling migration of remaining
integrations across adopter repos):

  1. All-three at Haiku >=80% composite (weak-model promise)
  2. Capability-only at Sonnet >=15pp lift over baseline
  3. Ontology-only at Sonnet >=10pp lift over baseline
  4. Harness-only at Sonnet >=10pp lift over baseline
  5. Combined-effects monotonicity (no variable degrades score)
  6. Locked-constraint adherence >=95% under prompt pressure

Missed criteria 1-4 by >5pp = pause rolling migration; missed
criteria 5-6 at all = stop and reconsider design. The shape of
the design survives single missed thresholds (tuning available);
deeper failures invalidate the value claim.

Ten-task seed mixing three categories:
- 5 generic tasks against synthetic fixture integrations
- 3 real-bug-derived tasks (incl. the Pipedrive /settings smell
  from the May 24-25 dev-feed thread)
- 2 adversarial locked-constraint pressure tests

Tasks are scored on four independent dimensions (correctness,
locality, constraint adherence, cost) and combined via weighted
composite. Per-task weight override available for adversarial
tasks where constraint adherence should dominate.

Build on promptfoo (Node-native, MIT, mature) with a custom
provider for the Frigg-agent-in-sandbox loop. ~1500 LOC total
including tests, scorers, fixtures, custom provider. Three-layer
ownership:
- @friggframework/evals: scorers + fixture integrations + generic
  tasks; published from the Frigg monorepo
- lefthookhq/quo--frigg/evals/ (and other adopters): real-
  integration tasks, importing scorers from the framework package
- Framework eval numbers are load-bearing for generality claims;
  adopter numbers are illustrative real-world demonstration

Cadence:
- Every PR: smoke test only (parse, validate, compile - no model
  calls; ~free, fast)
- On-demand: workflow_dispatch with --models, --tasks, --conditions
  knobs; ~$10-50 typical iteration
- Canonical at milestones: full 8x5x10 = 400 runs; $50-150 per
  canonical; committed to evals/results/ and inserted into this
  ADR's Canonical Results section
- Local dev: single-cell runs <$1

Rejected alternatives:
- Python-based Inspect AI: cross-language toolchain tax
- Adopter-only evals: can't make generality claims from one
  adopter's biased data
- Skip eval, ship on intuition: how the original
  integration-definition.schema.json shipped with zero adopters
- Eval on every PR: cost and latency untenable

Ten open questions captured, including task-set evolution,
model-version drift, scorer weight tunability, agent-loop
architecture (single-loop vs multi-agent simulation), per-condition
baseline (with vs without existing CLAUDE.md), and statistical
methodology (effect size + significance, not just p-values).

Canonical results section is templated; populated after first run
following ADR-INTEGRATION-CAPABILITIES Phase 4. None of the four
ADRs land on `next` until the canonical run exists.

Not yet PR-ready. Fourth adversarial reviewer (agent-eval value)
remains in flight; if/when it returns its findings inform a
follow-up revision to this ADR specifically.
- Scrub client-specific (Quo) and private-repo references; generalize
  vendor examples to HubSpot / Pipedrive / Salesforce / Slack.
- Add Module-exported ontology: api modules ship their own vendor L3
  fragments; integration projects compose from installed modules.
- Add Source adapters: compiler converts md / gdoc / notion / github /
  live sources to canonical records on the fly; distinguish source
  (authoring-time) from retrieve_from (runtime).
- Add Validation subagent pattern: recommended pass that spawns a
  subagent with the same compiled block to review parent agent output.
- Add Friction capture and ontology evolution: feedback loop that
  captures ambiguity / gaps / conflicts surfaced by agents and the
  validation subagent; backlog becomes the maintenance trigger.
- Reframe Phase 5 around module-exported ontology; add Phase 6 (source
  adapters), Phase 8 (friction tooling), renumber accordingly.
- Update Negative consequences to reference friction loop as the named
  defense against the "seed commits, ongoing edits stall" pattern.
- Add open questions on friction-tool naming and module-ontology rollout.
ADR-AGENT-HARNESS:
- Add Lifecycle taxonomy subsection mapping the 9-phase agent lifecycle
  (Freya ADR-008) onto Frigg touchpoints; clarify Frigg implements only
  the two phases Claude Code's hook surface exposes (SessionStart for
  parent pre_turn, SubagentStart for subagent pre_turn) and uses port
  decorators or skill conventions for the rest.
- Add decorator-vs-hook framing (decorators wrap ports for structural
  concerns; hooks punctuate the lifecycle for cross-cutting concerns).
- Add Shared friction pipeline subsection noting the @freyaframework/
  friction package as a co-owned dependency.

ADR-ONTOLOGY-LAYERS:
- Revise Validation subagent pattern to use Freya's discriminated-union
  return shape: {valid | fixable, correctionPrompt | friction, events}.
  FRICTION classification emits events into the shared pipeline.
- Replace abstract friction-tooling section with explicit borrow from
  Freya ADR-009 as @freyaframework/friction shared package. Itemize the
  v1 consumed surface (typed FrictionEvent with 6 starting signals,
  OntologyVcsPort + GitHubOntologyVcsAdapter, discriminated-union
  validation, threshold+corroboration+decay) and the v1 deferred surface
  (MigrationPlan, persisted FrictionCluster, confidence float, scheduled
  aggregator, multiple separate detection hooks, eight domain events).
- Lift the five non-negotiable guardrails verbatim (harness-side-only
  detection, human-approve-only, decay, rejection cooldown, cross-tenant
  isolation).
- Add positioning: bottom-up schema synthesis as the structural inverse
  of Hermes-style procedure synthesis.
- Update Open Q9 from "tool TBD" to "shared package decided; confirm
  trimmed v1 surface with Freya ADR-009 roadmap."
…ion package

- Generalize lefthookhq/quo--frigg and other client-repo references in
  ADR-INTEGRATION-CAPABILITIES, ADR-AGENT-HARNESS, and ADR-EVALS to
  "adopter repo / canary adopter project / participating adopter
  projects". The Frigg framework's ADRs are public; private client work
  doesn't belong inline. Vendor names (HubSpot, Pipedrive, Salesforce,
  Slack) preserved as examples since they're shipping api modules.
- Rename transformPersonToQuo example to transformPersonToDestination.
- Rename the second module in the worked example from "quo" to
  "destination" to preserve the renaming idiom without naming a client.
- Add cross-link from ADR-EVALS to ADR-ONTOLOGY-LAYERS friction
  subsection, noting eval miss-cases feed the shared
  @freyaframework/friction package as FrictionEvents.
Tier 3 Integration Extensions is now Implemented (PR #590 + PR #596).
Updates the ADR to reflect what actually shipped, while keeping Tier 1
(Core Plugins), Tier 2 (Application Extensions), Artifacts, and the
Capability Declaration as Proposed.

- Top-level Status: mixed; per-tier status spelled out
- Tier 3 section: explicit Implemented marker linking #590 + #596 +
  EXTENSIONS.md; quick-start in code is now authoritative for shape
- Extension contract example: useDatabase: false default added; route
  path updated to reflect binding-key namespacing
- Framework load mechanism: rewritten to document the URL pattern
  /api/{integration}-integration/{bindingKey}{route.path}, dedicated
  per-binding Lambda handlers, useDatabase resolution order
  (binding ?? extension ?? false), false-default scope (extension
  routes only — createHandler legacy paths still default true)
- Event vs route namespacing: clarified — routes are namespaced
  (since #596), events are not; same-event-name across bindings still
  throws; binding the same extension twice requires disjoint event sets
- Fail-loud defaults: amended with the useDatabase boolean validation
  and the new "two routes with same method+path within a single
  binding" framing
- Breaking change flagged for adopters: old un-namespaced webhook URLs
  must be re-pointed; HubSpot v3-style URL-signing schemes fail
  signature verification until updated
@sonarqubecloud

sonarqubecloud Bot commented Jun 2, 2026

Copy link
Copy Markdown

Add a `capabilities` array to `IntegrationBase.Definition` (and to subclass Definitions). Each entry declares:

- **`name`** — stable identifier for the capability, dot-namespaced by scope (`crm.initialContactSync`, `pipedrive.appUninstall`)
- **`primitive`** — taxonomy slot (see [Primitive taxonomy](#primitive-taxonomy))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no reference to primitive-taxonomy, please explain.


backedBy: {
spec: 'arazzo',
ref: '@friggframework/specs/crm/initial-contact-sync.arazzo.yaml',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would that yaml file look like?

},
},
{
name: 'pipedrive.adminScript',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this name come from? Does the user define this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants