diff --git a/docs/architecture-decisions/028-app-init.md b/docs/architecture-decisions/028-app-init.md new file mode 100644 index 000000000..cf599abae --- /dev/null +++ b/docs/architecture-decisions/028-app-init.md @@ -0,0 +1,129 @@ +# ADR-028: App Init + +**Status**: Proposed +**Date**: 2026-09-27 +**Deciders**: Sean Matthews + +## Context + +The other ADRs in this set describe what you build *inside* a Frigg app: plugins, extensions, integrations, capabilities, templates, artifacts. None of them describe how a Frigg app comes into existence. + +`frigg init` today produces a minimal scaffold. Adopters routinely then hand-configure the shape they actually want (which database plugin, which encryption method, which core extensions, which starter integrations, which L4 ontology conventions). Every adopter does the same setup by hand. Issue [#595](https://github.com/friggframework/frigg/issues/595) tracks the gap and flags the vestigial `--template` flag on the current implementation. + +**Project Templates** are distinct from [Integration Templates](./023-integration-templates.md). Integration Templates are per-category base classes an adopter copies into an existing app. Project Templates initialize the app itself. + +## Decision + +`frigg init` produces a Frigg app from a named **Project Template** plus an interactive interview that scaffolds overrides. The output is a working project with the adopter's plugin choices, seeded core extensions, seeded L4 ontology, and (optionally) a first reference integration. + +### Project Template registry (initial set) + +| Template | Posture | Use case | +|---|---|---| +| `minimal` | Bare skeleton. AWS provider, in-memory queue, no extensions, no reference integration. | Learning, experimentation | +| `production` | Postgres + KMS + private VPC + EventBridge scheduler + audit-log Core Extension + agent-frigg-claude Core Extension. Reference integration scaffolded. | Adopter shipping to prod | +| `agent-enabled` | Production posture plus MCP-server Core Extension, harness pre-configured, adopter skill and agent scaffolding under `.claude/`. | Adopter running agents against the codebase from day one | + +Adopters can publish additional templates under `@friggframework/project-template-*` or `@/project-template-*`. The registry is the same convention as [PLUGINS](./016-plugins.md) (`@friggframework/provider-*` etc). + +### Interview + +After template selection, `frigg init` walks the adopter through the choices that a template cannot pre-decide. Each answer writes into the generated `appDefinition`: + +| Question | Writes to | +|---|---| +| Database (Postgres / Mongo / DocumentDB / SQLite) | `plugins.database.kind` | +| Encryption (KMS / AES) | `plugins.encryption.kind` | +| Deploy target (AWS / Netlify / Vercel / GCP) | `plugins.provider.kind` | +| Auth modes (friggToken / sharedSecret / password / SSO) | `user.authModes` | +| Reference integration (skip / one from a menu / a partner-you-name) | Adds an [Integration Template](./023-integration-templates.md) copy under `backend/src/integrations/` | +| CI provider (GitHub Actions / none) | `.github/workflows/*` files | +| Changesets on/off | `.changeset/config.json` | + +Non-interactive mode: `frigg init --template production --answers answers.yaml` runs the same flow from a file. Both modes produce an identical result. + +### L4 ontology seed + +The init flow writes a starter `ontology/l4.yaml` derived from the interview answers. Example: + +```yaml +version: 1 +layer: L4 +domain: my-app +conventions: + - id: my-app.db + rule: "This app uses Aurora Postgres" + rationale: "Selected at init time" + - id: my-app.auth-modes + rule: "friggToken and sharedSecret are enabled; adopter apps must send x-frigg-api-key or a bearer JWT" +``` + +The seed is a small starting point. Adopters add to it over time as their conventions crystallize. See [ADR-021: Ontology](./021-ontology.md). + +## Shape (worked example) + +```bash +$ frigg init my-frigg-app --template production +✓ Copying production template into ./my-frigg-app/ +? Database › Aurora Postgres +? Encryption › AWS KMS (recommended for production) +? Deploy target › AWS +? Auth modes › friggToken, sharedSecret +? Add a reference integration? › Yes, HubSpot ↔ my adopter API (crm-sync-bidir) +? CI provider › GitHub Actions +? Changesets › Enable +✓ Wrote appDefinition to backend/index.js +✓ Wrote L4 ontology seed to ontology/l4.yaml +✓ Scaffolded reference integration at backend/src/integrations/HubspotSync/ +✓ Wrote CI workflows to .github/workflows/ +✓ Ran npm install +✓ Ran `frigg auth test .` on scaffolded modules. All pass. +ℹ Next: map your adopter API in backend/src/integrations/HubspotSync/mapping.js +``` + +## Architecture + +```mermaid +flowchart LR + subgraph Registry["Project Template registry"] + T1["minimal"] + T2["production"] + T3["agent-enabled"] + T4["@org/project-template-*"] + end + subgraph Cli["frigg init"] + Sel["template select"] + Int["interview
(db, encryption, provider,
auth, reference integration,
CI, changesets)"] + end + subgraph Output["Generated app"] + Def["appDefinition.plugins
appDefinition.extensions"] + Ont["ontology/l4.yaml (seed)"] + Int1["backend/src/integrations/*
(from Integration Template)"] + Ci[".github/workflows/*"] + end + Registry --> Sel + Sel --> Int + Int --> Def & Ont & Int1 & Ci +``` + +## Cross-references + +- [PLUGINS](./016-plugins.md): interview answers write into `plugins.*` selections +- [CORE-EXTENSIONS](./017-core-extensions.md): Project Templates preload zero or more Core Extensions +- [INTEGRATION-TEMPLATES](./023-integration-templates.md): reference integration option delegates to Integration Templates +- [ONTOLOGY](./021-ontology.md): the L4 seed is a starting point for adopter-owned conventions +- [SKILLS](./029-skills.md): agent-enabled template scaffolds `.claude/` with a starter skill and agent set + +## Open questions + +1. **Template distribution.** npm package (`@friggframework/project-template-production`) vs git URL (`--template github:org/repo`) vs both? Lean: npm primary, git URL supported for org-private templates. +2. **Template inheritance.** Can `agent-enabled` be defined as `production` + a delta, or must every template be self-contained? Lean: self-contained; delta introduces a compatibility matrix. +3. **Interview UX.** JSON Schema form (like `frigg auth test`) vs inquirer prompts? Lean: JSON Schema for consistency with the rest of the CLI. +4. **Re-run behavior.** `frigg init` in an existing directory: error, refuse, or `--reconfigure` to update overrides without touching custom code? Lean: refuse unless `--reconfigure` is passed. +5. **The vestigial `--template` flag.** The current implementation has a `-t, --template` option that falls through to a "Legacy template system is no longer supported" error path (issue #595). Remove it, or repurpose it to select from the new registry? Lean: repurpose. + +## References + +- Issue [#595](https://github.com/friggframework/frigg/issues/595): the proposal that motivated this ADR +- Issue [#594](https://github.com/friggframework/frigg/issues/594): related docs drift on the CLI command list +- Existing production Frigg projects at adopters have converged on a common posture (Postgres + KMS + VPC + EventBridge + Changesets + GitHub Actions). That converged shape is the prior art for the `production` Project Template proposed here. diff --git a/docs/architecture-decisions/029-skills.md b/docs/architecture-decisions/029-skills.md new file mode 100644 index 000000000..e39ddd7b0 --- /dev/null +++ b/docs/architecture-decisions/029-skills.md @@ -0,0 +1,131 @@ +# ADR-029: Skills + +**Status**: Proposed +**Date**: 2026-09-27 +**Deciders**: Sean Matthews + +## Context + +Adopter Frigg apps that use agents (Claude Code, Cursor, custom orchestrators) ship a `.claude/skills/` directory alongside `.claude/agents/`. Skills are the read-on-demand knowledge, contracts, and runbooks that agents load into context. The [ADR-025: Agent Harness](./025-agent-harness.md) proposes a runtime hook that injects compiled ontology + capability data at session start. Skills are the complementary declarative surface: knowledge and procedures the agent can load explicitly when relevant. + +An adopter repo that uses Frigg for repeated CRM integration authoring has an in-production skill layer with three sub-agents and five skills. Reading its actual files surfaces a distinction the current ADR set does not name: skills have distinct subtypes with different lifecycles and different authoring roles. Bundling them under one word obscures which pattern applies when. + +## Decision + +A **Skill** is a Markdown-fronted directory under `.claude/skills//` containing a `SKILL.md` with YAML frontmatter (`name`, `description`, optional `user-invocable`, optional `argument-hint`) plus supporting files. Skills are one of four subtypes: + +| Subtype | What it contains | Example | Loaded by | +|---|---|---|---| +| **Knowledge skill** | Reference material (an L3 or L4 [Ontology](./021-ontology.md) fragment). Ref files per stage. Hard rules. Gotchas. Gold-standard exemplars. | `{adopter}-integration-ontology` | Any agent, preloaded via `skills:` frontmatter | +| **Contract skill** | JSON Schema + template + validator. The machine-checkable shape of a handoff artifact. | `{adopter}-spec-contract` | Producer and consumer agents in a pipeline | +| **Runbook skill** | Human-executable procedure. Scripts, templates, step-by-step. | `{adopter}-test-integration`, `{adopter}-changeset` | User or agent per-invocation | +| **Recipe skill** | Multi-phase orchestration with embedded knowledge and procedure. | `frigg-create-integration` | User or top-level agent | + +### The `user-invocable` flag + +Skills default to user-invocable. Set `user-invocable: false` in frontmatter to hide the skill from user-facing lists. Sub-agent-only knowledge and contract skills should set this so they do not appear as CLI options; they exist as agent preload material only. + +### Skill-to-agent preloading + +A sub-agent declares which skills to preload via the `skills:` field in its frontmatter: + +```yaml +--- +name: spec-author +description: Authors an integration spec from a third-party API's docs. +tools: Read, Grep, Glob, WebFetch, Write, Bash +model: opus +skills: + - {adopter}-integration-ontology + - {adopter}-spec-contract + - frigg +--- +``` + +The framework loads the referenced skills' `SKILL.md` and any explicitly-referenced reference files into the agent's context at spawn time. Reference files under the skill's directory (`reference/*.md`) are read on demand by the agent, not eagerly loaded. + +This declarative form is a valid alternative to the [Agent Harness](./025-agent-harness.md) hook for grounding an agent. The harness compiles a merged ontology + capability graph at session start; `skills:` frontmatter loads specific named skills at agent spawn. Both mechanisms coexist. The harness handles cross-cutting context; `skills:` handles agent-specific bundles. + +## Shape (worked example) + +Directory layout for the four subtypes: + +``` +.claude/skills/ +├── {adopter}-integration-ontology/ # knowledge skill +│ ├── SKILL.md # user-invocable: false +│ └── reference/ +│ ├── base-crm-integration.md +│ ├── api-module.md +│ ├── gotchas-checklist.md +│ ├── hcp-gold-standard.md +│ ├── house-style.md +│ └── {vendor}-module.md +├── {adopter}-spec-contract/ # contract skill +│ ├── SKILL.md # user-invocable: false +│ ├── schema/spec.schema.json # the JSON Schema +│ └── templates/spec-template.md # a human-readable render template +├── {adopter}-test-integration/ # runbook skill +│ ├── SKILL.md # argument-hint: "[spec-path] [local|dev]" +│ ├── scripts/run-lifecycle.sh +│ └── templates/test-report.template.json +└── frigg-create-integration/ # recipe skill + ├── SKILL.md + ├── assets/ + └── references/ +``` + +## Architecture + +```mermaid +flowchart TB + subgraph Skills[".claude/skills/"] + K["Knowledge skill
(L3/L4 ontology fragment)"] + C["Contract skill
(JSON Schema + template)"] + R["Runbook skill
(scripts + templates)"] + Rc["Recipe skill
(multi-phase orchestration)"] + end + subgraph Agents[".claude/agents/"] + A1["spec-author
skills: [ontology, contract]"] + A2["build-engineer
skills: [ontology, contract, recipe]"] + A3["adversarial-reviewer
skills: [ontology]"] + end + subgraph Adopter["Adopter developer"] + U["frigg CLI or agent invocation"] + end + K -- "preloaded via `skills:`" --> A1 & A2 & A3 + C --> A1 & A2 + Rc --> A2 + R -- "invoked directly" --> U + U -- "spawns" --> A1 & A2 & A3 +``` + +## Authoring guidance for adopters + +When authoring a skill layer for a new adopter app: + +1. **Start with the knowledge skill** (`-integration-ontology`). Capture framework contract facts, house style, gotchas, and a gold-standard exemplar. This is the L3+L4 [Ontology](./021-ontology.md) fragment. +2. **Add the contract skill** (`-spec-contract`) if you have a repeated authoring flow that hands off between phases (scoping → building → testing). Ship the JSON Schema, a template, and a validator. +3. **Add runbook skills** for procedures the human runs directly (`-test-integration`, `-changeset`, `-deploy`). +4. **Compose sub-agents** in `.claude/agents/` that reference the skills via `skills:` frontmatter. See [ADR-030: Agent Pipeline](./030-agent-pipeline.md). + +## Cross-references + +- [ONTOLOGY](./021-ontology.md): knowledge skills are the concrete surface for L3 and L4 ontology fragments +- [CAPABILITIES](./020-capabilities.md): a contract skill can be the JSON Schema that a capability's `spec.ref` points at +- [AGENT-HARNESS](./025-agent-harness.md): harness compiles cross-cutting context; `skills:` frontmatter loads agent-specific bundles. Complementary. +- [AGENT-PIPELINE](./030-agent-pipeline.md): pipelines are composed from sub-agents that preload skills +- [APP-INIT](./028-app-init.md): the `agent-enabled` Project Template scaffolds a starter skill layer + +## Open questions + +1. **Skill discovery convention.** `@friggframework/skill-*` packages? Both npm and in-repo `.claude/skills/`? Lean: both, with in-repo taking precedence when both are present. +2. **Skill versioning.** Do skills carry their own version, or inherit from the package that ships them? Lean: inherit; skills change with the framework or adopter code they document. +3. **Reference-file eager vs lazy loading.** `SKILL.md` loads eagerly at agent spawn; `reference/*.md` reads on demand. Is that the right split, or should some reference files also load eagerly? Lean: current split. +4. **Contract-skill validators.** Do contract skills ship a Node validator, a JSON Schema alone, or both? Lean: schema is authoritative; validator is a convenience. +5. **Cross-adopter skill reuse.** If ten adopter apps end up shipping similar `-changeset` runbook skills, should the common shape move into a shared `@friggframework/skill-changeset`? Lean: yes, once three adopters converge on the same shape. + +## References + +- An adopter repo running the pattern in production has five skills (one knowledge, one contract, three runbook / recipe) and three sub-agents. The five-skill, three-agent shape is the reference implementation for this pattern. +- Anthropic's Claude Code documentation on skills and agents is the framework this ADR builds on. diff --git a/docs/architecture-decisions/030-agent-pipeline.md b/docs/architecture-decisions/030-agent-pipeline.md new file mode 100644 index 000000000..13a1e047e --- /dev/null +++ b/docs/architecture-decisions/030-agent-pipeline.md @@ -0,0 +1,137 @@ +# ADR-030: Agent Pipeline + +**Status**: Proposed +**Date**: 2026-09-27 +**Deciders**: Sean Matthews + +## Context + +The [Agent Harness](./025-agent-harness.md) grounds a single agent's session with compiled ontology and capability context. The [Skills](./029-skills.md) layer lets agents preload adopter-specific knowledge and contracts. Neither addresses how multiple agents compose into a workflow with typed handoffs. + +An adopter demonstrates a three-agent pipeline in production: a spec-author produces a spec, a build-engineer consumes that spec and implements the integration, an adversarial-reviewer refutes-by-default against a gold-standard exemplar. Each phase has its own model, tools, and role. The handoff between phases is a machine-checkable artifact validated against a JSON Schema. + +The pattern is general to any repeated integration authoring flow that benefits from splitting scoping from building from reviewing. This ADR names the shape and cross-references the pieces that compose it. + +## Decision + +An **Agent Pipeline** is a sequence of sub-agents with typed handoffs. Each agent has a defined role, model tier, tool restriction, and preloaded skill set. The output of one phase is the input to the next, validated against a [Contract Skill](./029-skills.md) schema. + +### Canonical three-phase pipeline + +``` +scope-author → build-engineer → adversarial-reviewer +``` + +| Phase | Role | Model | Tools | Preloaded skills | +|---|---|---|---|---| +| Scope | Author the spec from third-party API docs + adopter ontology | opus (creative discovery) | Read, Grep, Glob, WebFetch, Write, Bash | ontology, contract, recipe | +| Build | Implement the spec | sonnet (mechanical) | Read, Write, Edit, Bash, Grep, Glob | ontology, contract, recipe | +| Review | Refute the artifact meets the quality bar | opus (skeptical judgment) | Read, Grep, Glob, Bash (`disallowedTools: Write, Edit`) | ontology | + +Model tiering is intentional. Scoping and adversarial review benefit from a stronger model because both require judgment. Building is mechanical once the spec exists and works well at a smaller model. + +### The read-only adversary + +The reviewer is structurally read-only via `disallowedTools: Write, Edit`. The reviewer cannot patch the artifact it critiques. The framework enforces this at spawn time. + +Review calibration: + +- Default to skeptical. A finding is "PASS" only if the reviewer genuinely could not refute it. +- Findings cite file:line or the spec field. Free-form judgment without an anchor is not a valid finding. +- Explicit `openQuestions` in the spec are NOT defects. They are the human-decision surface. The reviewer only raises a question if the spec should have answered it from the available API docs. +- Over-engineering and verbosity are penalized as hard as gaps. Speculative abstractions and unrequested config fail review. + +### Typed handoffs + +The output of each phase is validated against a [Contract Skill](./029-skills.md) schema: + +- Scope → Build: `specs/.spec.json` conforms to `spec.schema.json` +- Build → Review: the codebase diff plus the spec ID +- Review → Build (on refutation): a findings JSON conforming to `review.schema.json` with `{finding_id, file, line, category, severity, rationale}` + +Contract skills ship the schemas alongside human-readable templates. Both are versioned with the adopter's skill package. + +### EARS acceptance criteria + +The spec declares acceptance criteria in [EARS](https://alistairmavin.com/ears/) form: + +```json +{ + "acceptanceCriteria": [ + { "id": "AC-1", "statement": "WHEN a new contact is created in HubSpot THE SYSTEM SHALL upsert the corresponding destination CRM contact within 30 seconds" }, + { "id": "AC-2", "statement": "WHEN the third-party OAuth refresh fails THE SYSTEM SHALL mark the integration as ERROR and stop further sync attempts" } + ] +} +``` + +The build agent tags each test with the matching `AC-n` id. The trace from requirement to test survives the pipeline and is grepped by the reviewer. + +## Architecture + +```mermaid +flowchart LR + subgraph Scope["Scope phase (opus)"] + S["spec-author"] + end + subgraph Build["Build phase (sonnet)"] + B["build-engineer"] + end + subgraph Review["Review phase (opus, read-only)"] + R["adversarial-reviewer"] + end + Docs["Third-party API docs
+ adopter ontology"] --> S + S -- "specs/*.spec.json
(validates against
spec.schema.json)" --> B + B -- "diff + tests tagged AC-n" --> R + R -- "refutation
(review.schema.json)" -.-> B + R -- "PASS" --> Ship["Merge → deploy"] +``` + +Adversarial-review refutations loop back to the build agent, which patches and re-submits. The pipeline terminates when the reviewer returns PASS. + +## Shape (worked example) + +Invoking the pipeline from the top-level agent or CLI: + +```bash +$ frigg pipeline run integration --partner hubspot --name HubspotSync +Phase 1/3: Scoping + → spec-author (opus) authoring specs/hubspot-sync.spec.json + ✓ Spec validated against spec.schema.json (12 AC, 8 gotchas addressed) +Phase 2/3: Building + → build-engineer (sonnet) implementing from spec + ✓ Generated backend/src/api-modules/hubspot/ (api.js, definition.js) + ✓ Generated backend/src/integrations/HubspotSyncIntegration.js + ✓ Generated tests (12 tagged AC-1 through AC-12) +Phase 3/3: Reviewing (adversarial) + → adversarial-reviewer (opus, read-only) via 3 lenses: correctness, gotchas, simplicity + ✗ FAIL: AC-7 test missing rate-limit assertion; over-engineered retry helper (lens: simplicity) +Loop back to Phase 2: + → build-engineer patching per review findings + ✓ AC-7 test now asserts rate-limit backoff; retry helper removed +Phase 3/3: Reviewing (retry) + ✓ PASS: all three lenses cleared +Pipeline complete. Ready to merge. +``` + +## Cross-references + +- [AGENT-HARNESS](./025-agent-harness.md): each agent in the pipeline is grounded by the harness at spawn (compiled ontology + capabilities). The pipeline composes agents; the harness grounds them. +- [SKILLS](./029-skills.md): each agent preloads knowledge, contract, and recipe skills via `skills:` frontmatter +- [CAPABILITIES](./020-capabilities.md): the spec-contract schema is what a capability's `spec.ref` can point at when the capability is implemented by an agent-produced integration +- [ONTOLOGY](./021-ontology.md): the reviewer refutes against ontology-encoded conventions and locked constraints +- [APP-INIT](./028-app-init.md): the `agent-enabled` Project Template scaffolds a starter pipeline + +## Open questions + +1. **Pipeline runner.** Where does the pipeline orchestrator live? A `frigg pipeline` CLI command, a Claude Code agent workflow, an SDK API, or all three? Lean: CLI command that spawns agents in sequence. +2. **Retry ceiling.** How many review → build → review loops before human escalation? Lean: 3, configurable. +3. **Parallel review lenses.** The `adversarial-reviewer` reviews through one lens at a time. Should the framework run multiple lens instances in parallel and merge findings? Lean: yes, parallel, merged deterministically. +4. **Cross-adopter pipeline reuse.** Are pipelines adopter-specific or general (`frigg-integration-pipeline`)? Lean: start adopter-specific, generalize once three adopters converge on the same shape. +5. **Failure attribution.** If a review fails, does the framework attribute the failure to the build agent, the spec, or the ontology? Lean: attribute to the earliest phase whose artifact would need to change to resolve the finding. +6. **Human-in-the-loop points.** Where can (or must) a human intervene? Lean: after scoping (approve spec), after successful review (approve merge), never during a phase. + +## References + +- An adopter running the pattern in production ships `spec-author.md`, `build-engineer.md`, and `adversarial-reviewer.md` under `.claude/agents/` as the reference implementation. +- [EARS](https://alistairmavin.com/ears/): Easy Approach to Requirements Syntax; the acceptance criteria form. +- Anthropic's Claude Code sub-agent documentation. diff --git a/docs/architecture-decisions/README.md b/docs/architecture-decisions/README.md index bc7c9bfbb..e709955fc 100644 --- a/docs/architecture-decisions/README.md +++ b/docs/architecture-decisions/README.md @@ -43,6 +43,9 @@ An ADR documents a significant architectural decision made in the project, inclu | [024](./024-global-entities.md) | Global Entities | Proposed | 2024-12-18 | | [025](./025-agent-harness.md) | Agent Harness | Proposed | 2026-06-09 | | [026](./026-evals.md) | Evals | Proposed | 2026-06-09 | +| [028](./028-app-init.md) | App Init | Proposed | 2026-09-27 | +| [029](./029-skills.md) | Skills | Proposed | 2026-09-27 | +| [030](./030-agent-pipeline.md) | Agent Pipeline | Proposed | 2026-09-27 | ## Conventions