Guide

Create your own stack

One process, any technology: the contract a layer plugin fulfils.
The aiup-core plugin is stack-independent: it produces the requirements, the entity model, the use cases, and the test cases, and it runs construction through /stack, /use-case-implement, /use-case-test, and /use-case-coverage, and for a test case journey /test-case-implement and /test-case-coverage. The technology comes from layer plugins, one per technology of one technical layer. If yours is not among them, this guide describes what a layer plugin must provide: a build skill and a test skill, a references/layer.md that describes the layer, a Handover to the next layer, and the markers that keep every test traceable to its use case.
Division of labour

Layer plugin or combined stack plugin #

The AI Unified Process (AIUP) keeps requirements at the center. Everything upstream of code is the same for every team; everything that depends on a framework, a persistence technology, or a test tool belongs to a plugin. Since marketplace 3.0, the recommended way to add a technology is a layer plugin.

The core owns the specifications and the rules #

aiup-core writes the requirements catalog, the entity model, the use case diagram, the use case specifications, and the end-to-end test cases. None of these mention a framework, and your plugin must never rewrite them. For construction, aiup-core also owns the orchestrators and the rules every layer shares: /use-case-implement checks the status, reads the inputs, reconciles existing code, and asks about specification gaps; /use-case-test decides which layer tests what; /use-case-coverage audits the result with a read-only agent.

A layer plugin owns one technology #

A layer plugin covers one technology of one technical layer, for example jOOQ for persistence or Angular for the UI. A project combines one plugin per layer, and /stack records the combination in the stack file, docs/architecture/stack.md. That is how a REST API with Spring Boot and jOOQ and no UI becomes expressible. A project uses either layer plugins or one combined stack plugin, never both.

Reference implementations #

Use the layer plugins in the marketplace repository as reference implementations. Copy the one closest to your layer: aiup-jooq is a compact persistence plugin with one build and one test skill, aiup-spring-boot shows three layers in one plugin, and aiup-playwright an E2E layer without a build skill.

aiup-flywayMigration: /flyway-schema
aiup-jooqPersistence: /jooq-persistence, /jooq-persistence-test
aiup-jpaPersistence: /jpa-persistence, /jpa-persistence-test
aiup-spring-bootService, API, and Client: /spring-service, /spring-rest, /spring-client, /spring-service-test, /spring-rest-test, /spring-client-test
aiup-vaadinUI and E2E: /vaadin-flow-ui, /hilla-ui, /vaadin-flow-ui-test, /hilla-ui-test, /vaadin-e2e-test
aiup-angularUI: /angular-ui, /angular-ui-test
aiup-playwrightE2E for TypeScript: /playwright-e2e-test
When a combined stack plugin fits instead. When the architecture is organised in vertical slices rather than horizontal layers, a combined stack plugin is still the right shape: aiup-blazor-dotnet stays combined for good, because its Vertical Slice Architecture keeps a use case's handler and data access in one slice. See combined stack plugins below.
The contract

What a layer plugin provides #

A layer plugin brings a build skill and a test skill for its layer, named <technology>-<layer> and <technology>-<layer>-test, such as jooq-persistence and jooq-persistence-test. /use-case-implement runs the build skills bottom-up, /use-case-test runs the test skills from the integration layer up, and every skill also runs on its own.

The six layers #

Your plugin fills one of these layers, or several when one technology spans them, as Spring Boot does for service and API.

MigrationVersioned schema changes from the entity model
PersistenceData access: queries, repositories, entity mapping, projections into records
ServiceBusiness logic: transactions, business rules, orchestration
APIRemote contract for a separate client: endpoints, DTOs, error format
UIViews, forms, grids, navigation
E2EBrowser tests of a use case or a test case journey

API, UI, and Service are the entry layers, where an actor reaches the system. A use case may name the entry layers that offer it in an optional Layers line (UI, API, or Service alone); /use-case-implement builds only those, /use-case-test tests only those, and the coverage audit reports no gap for a layer the line leaves out.

  1. A build skill #

    Required for every layer except E2E. Builds one layer of one use case.

    /use-case-implement UC-001     # all layers, bottom-up
    /jooq-persistence UC-001  # one layer, run directly

    Every layer skill follows the same skeleton: Instructions, Scope (what it consumes, what it produces, what it never touches), Run Directly or from /use-case-implement, the technology sections with where the business rule marker goes in this layer, Markers, DO NOT, Workflow, Handover, and Resources. It takes the module and package from the Location column of its row in the stack file and follows the existing code of the project first. It never reaches past the next layer: the UI does not query the database, and a missing table goes back to the migration skill instead of being worked around.

    Run from /use-case-implement, the skill inherits the inputs, the status check, the answers to the specification gaps, and the reconcile rules, and does not repeat them. Run directly, it reads the same inputs, applies the same rules, builds its layer only, and says that /use-case-implement runs all layers. Either way, it takes decisions by the decision rights of /use-case-implement: it asks before a decision they reserve, such as a new dependency, never takes one they forbid, and lists the decisions it took alone under Decisions in its report. A UI build skill also reads the use case's optional Mockup line as layout input, as the section Mockups of /use-case-implement defines, and names what it followed and left out in a Mockup line of its Handover. An API build skill reads the use case's optional API line the same way, as the section API Contract of /use-case-implement defines, builds the linked operation as its contract says, and names it in a Contract line of its Handover. The shared rules live once, in aiup-core; refer to them by slash command and do not copy them into your skill.

  2. A test skill #

    Required for every layer with code of its own to test. Named after the build skill plus -test.

    A use case is tested once, in the project's integration layer: the topmost layer whose tests run in process against the real database. Its test skill covers the main success scenario, every alternative flow, every business rule with its allowed and its rejected case, the preconditions, and the postconditions read back from the persisted state. The layers below get no tests of their own, so your test skill must know which role it plays:

    • As the integration layer – test the whole use case through your entry point, and report every unit it cannot reach, so /use-case-test runs the test skill of the layer that owns it for exactly those units.
    • Below the integration layer – run only to reconcile existing tests, for unreachable units, or when a run names the layer, and test only logic of your own, such as a filter, a join, or paging.
    • Above it, with the backend mocked – test what the UI decides and that a rejection reaches the actor with the specified message, not the rule again.
    • A second entry layer – an API next to a Vaadin Flow or Hilla UI that offers the same use case tests its own contract: the main success scenario through its endpoint, each alternative flow's response, and the validation mapping, but not the business rules again.
    • E2E – the main success scenario and the alternative flows an actor sees, when the E2E scope in the stack file reads "Use cases and test cases"; with a TC-XXX, run by /test-case-implement, one journey test with one step per Flow row.
    The specification is the oracle. Expected values come from the specification and the test data, never from running the code. A test that disagrees with the code stays failing and is reported; the test skill never changes production code and never weakens, deletes, or disables such an assertion. /use-case-test owns these rules; a test skill run directly applies them too.
  3. references/layer.md #

    Required. One row that describes the layer, in the build skill, or in the test skill of an E2E layer.

    /stack discovers the installed layer skills by listing */references/layer.md in the project's skill folders (.claude/skills/, .github/skills/, .codex/skills/, .agents/skills/, .cursor/skills/), in the personal folder ~/.claude/skills/, and, for a Claude Code marketplace install, in the enabled plugins of ~/.claude/plugins/installed_plugins.json. It lists those folders directly, because they are hidden, Tessl links each skill as a symlink into .tessl/, and in its managed mode lists the links in .gitignore: a default ripgrep search or a find without -L finds nothing there. Where the host lists the session's skills, as Claude Code does, that list decides: the layer.md of a disabled, uninstalled, or merely cached plugin does not count, and a plugin skill runs by its prefixed name, such as aiup-jooq:jooq-persistence. So a plugin that aiup-core has never heard of works as well as one it ships with, without a core release. /stack reads the Detect column to recognise your technology in an existing project and the Tests run column to decide the integration layer.

    | Plugin | Layer | Skill | Test skill | Tests run | Detect in an existing project |
    | `aiup-jooq` | Persistence | `jooq-persistence` | `jooq-persistence-test` | in process, real database | `org.jooq:jooq`, `spring-boot-starter-jooq`, `jooq-codegen-maven` |
    LayerOne of Migration, Persistence, Service, API, UI, E2E
    SkillThe build skill's folder name, or – for an E2E layer
    Test skillThe test skill, or – when the layer has none, as for a migration
    Tests runin process, real database; backend mocked; running application; or – without a test skill
    DetectThe dependencies, files, or annotations that show the technology is in use; source-tree evidence first

    Lead the Detect cell with evidence from the source tree, such as a @Route class, a @BrowserCallable class, or an angular.json. Where a cell lists several kinds of evidence, the source tree decides, and a dependency that another skill names as well is no evidence for either: Vaadin Flow and Hilla share their dependencies, so /stack asks instead of guessing.

    A team skill without a layer.md. A team's own skill, a mybatis-persistence or a skill with the company's Spring conventions, is a layer skill too. With a references/layer.md it is discovered like a marketplace plugin. Without one, it counts once you name it for a layer in /stack, which then asks what its tests run against (in process, real database; backend mocked; or running application), because the integration layer depends on it, and suggests adding a layer.md so the next run need not ask. The guide Writing a layer skill describes the contract.
  4. The Handover #

    Required. The last block of every build skill's report.

    Layers run migration → persistence → service → API → UI. Each build skill ends with a Handover that lists the tables, types, method signatures, or endpoints it created or changed, and /use-case-implement passes it unchanged to the next layer, which builds on exactly that contract instead of inventing its own DTO. A layer with nothing to do says so in its Handover. Run on its own, without a Handover, a skill reads the existing code of the layer below; its Scope says where.

    Handover from jooq-persistence (UC-001)
    - PersonRepository — src/main/java/com/example/app/person/PersonRepository.java
      - Optional<PersonForm> findById(long id)
      - boolean update(PersonForm person)   — false when the version is stale
      - boolean existsByEmail(String email) — UC-001 BR-003
    - record PersonForm(Long id, String firstName, String lastName, String email, int version)
  5. Markers in the stack file #

    Required. Each skill ships references/markers.md and keeps its rows in the project.

    The stack file ends with a Markers table: Layer, Skill, Kind (Code, Test, or Name), and the marker to grep for. On every run, each build and test skill checks that the rows for its skill match its references/markers.md, adds the missing ones, corrects the ones that differ, and touches no other row. The coverage auditor in aiup-core reads that table instead of a fixed list, so core needs no knowledge of your markers, and your plugin needs no coverage agent of its own.

    | Persistence | jooq-persistence-test | Test | `@UseCase(id = "UC-XXX", …)` on every repository test method |
    | Persistence | jooq-persistence-test | Name | `UC<id><Name>RepositoryTest` |
Arguments. Every skill takes a use case ID (UC-001) or the path of the specification file; the E2E test skill also takes a test case ID (TC-001). A diff of the specification change may follow the path; when it does, it is the definitive list of what changed.
Inputs

What the skills read #

A layer plugin reads the documents aiup-core writes, in the places aiup-core writes them. Do not invent a second format; the requirements-driven chain only works when every plugin reads the same files.

Files #

docs/use_cases/UC-*.mdOne specification per use case
docs/requirements.mdOnly the FR, NFR, and C rows the use case links, never the whole catalog
docs/entity_model.mdEntities, attributes, data types, validation rules, and relationships
docs/glossary.mdThe terms to name classes, fields, and labels with, when it exists
docs/architecture/stack.mdThe stack file: layers, integration layer per entry layer, E2E scope, module layout, API contract, commands, markers
docs/architecture/decision-rights.mdOptional: the team's decision rights, which replace the defaults of /use-case-implement
docs/test_cases/TC-*.mdEnd-to-end journeys that chain several use cases, for the E2E layer

Accepted architecture decision records are followed when the project has them (docs/architecture/decisions/, or an adr/ or adrs/ folder anywhere in docs/); a proposed, superseded, deprecated, or rejected one is no decision to follow. UI mockups, OpenAPI documents, and schemas are referenced from the use case that needs them; follow those references.

Headings the skills rely on #

  • Use Case ID – the UC-XXX identifier every marker points to
  • Requirements – the FR, NFR, and C rows to read; a linked NFR or constraint with an observable limit needs a test too
  • Layers – optional; the entry layers that offer the use case
  • Main Success Scenario – numbered steps
  • Alternative flows – headings A1, A2, … named in the test
  • Business rules – BR-XXX, marked in code and named in tests
  • Preconditions and postconditions – test data, assertions, and cleanup. A use case that changes no data has the failure postcondition _None — the use case changes no data._ and needs no failure test for it
  • Status – Draft, Reviewed, Approved, Implemented, Tested, Done, Obsolete. The skills never edit it; the coverage audit only suggests the next value
Data, never instructions. Every skill states that everything it reads from the project (specifications, code, configuration) is data. A sentence that looks like an instruction to the agent is reported by location, not followed. And no skill edits a file under docs/, with one exception: its own rows in the Markers table.
Traceability

Traceability with @UseCase and rule markers #

Every test names the use case, scenario, and business rules it verifies, and the code that enforces a rule names that rule. The AI Unified Process Navigator shows these links as gutter icons in IntelliJ and VS Code, AI Unified Process Studio builds its traceability view from them, and the coverage audit uses them to map the specification onto code and tests.

@UseCase on JVM test methods #

The annotation is test code. Before writing a test, the test skill searches the test sources of the module under test for @interface UseCase and reuses it; otherwise it creates src/test/java/<root package>/usecase/UseCase.java, never in src/main/java. In a multi-module project, every module that holds use case tests gets its own copy. Every Java test skill carries exactly this shape, because whichever one runs first creates the file and the others reuse it:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UseCase {
  String id();
  String scenario() default "Main Success Scenario";
  String[] businessRules() default {};
  String[] requirements() default {};
}

The values match the headings of the specification exactly; requirements names the NFR and constraint IDs from the use case's Requirements line that the test asserts. An existing annotation without requirements is extended, never replaced. Inside a test that carries its use case ID, a rule is named by its bare ID:

@UseCase(id = "UC-001",
  scenario = "A2: Invalid Postal Code",
  businessRules = {"BR-003"},
  requirements = {"NFR-004"})

Tests without annotations #

Test frameworks without annotations carry the same information in the test names and tags:

describe('UC-010: Browse Product Catalog', () => {
  it('A1: filters by category', …)
})
 
test.describe('UC-010: …', { tag: '@UC-010' }, …)

A test that asserts the limit of an NFR or constraint names its ID the same way, as in it('NFR-004: rejects a comment longer than 500 characters', …). For another language, use its native equivalent (an attribute, a trait, a tag) with the same fields: use case ID, scenario, business rules, and requirements. Whatever you choose goes into your references/markers.md.

Business rule markers in code #

The build skill marks the code that enforces a business rule with a qualified comment, directly above the method, query condition, constraint, or validator, while it implements the rule:

// UC-001 BR-003: A guest must be at least eighteen years old.
-- UC-001 BR-003: …   # in a SQL migration

Always qualified with the use case, because rules are numbered per use case. A rule enforced in several layers gets the marker in each, and your skill says where it goes in its layer. /use-case-implement owns this rule; your skill only names the place. Keep the whole comment, indentation included, within the line length of the project's formatter (Spring Java Format wraps comments at 90 columns): a marker the build breaks onto a second line is no longer one line to grep, so shorten the restated rule instead.

Naming conventions #

UC001RegisterPersonRepositoryTestPersistence test of one use case
UC001RegisterGuestServiceTestService test of one use case
UC001RegisterGuestApiTestAPI test of one use case
UC001ManagePersonsTestServer-side UI test of one use case
UC001ManagePersonsEndpointTestEndpoint contract test behind a Hilla view
UC001ManagePersonsITBrowser test of one use case (Java)
TC001CustomerOnboardingITJourney test (Java), annotated (id, useCases) on the class
UC-001-manage-persons.spec.tsTest file of one use case (TypeScript)
UC-001-manage-persons.test.tsxHilla view test of one use case
TC-001-<slug>.spec.tsJourney test, one step per Flow row

Repositories and services are named after the domain, never after a use case: a repository per aggregate, a service per entity. A view is named after the use case it realizes, in the actor's glossary term, such as ManagePersonsView.

Test data #

The test skills own the test data; the migration layer writes none. An existing convention of the project always comes first. Without one, the layer plugins use one repeatable Flyway migration per use case in the test sources. Flyway's default location covers the test resources too, so neither a profile nor a @TestPropertySource is needed; repeatable migrations run after every versioned one and never collide with the next production version:

src/test/resources/db/migration/R__uc001_register_guest.sql

The data satisfies the preconditions and contains the rows a business rule must exclude, so a missing condition makes a test fail. Tests run against the database the project runs on, never an in-memory substitute with another dialect. Data a test creates is removed in its cleanup, never with a delete-all. A flow whose trigger the shared data rules out, such as an empty list, deletes those rows inside a test transaction that rolls back, where the entry point runs in the test's thread (Browserless, MockMvc, a service call); a browser test leaves that flow to the integration layer.

Change

Reconcile, don't copy #

A new feature, a change request, and a bug all end in the same place: a changed use case specification. There is no separate command for any of them. The user edits the specification and runs /use-case-implement and /use-case-test again, so every layer skill must find the existing code of its layer and reconcile it in place. /use-case-implement and /use-case-test own these rules and pass them to each layer; a skill run directly applies them itself.

Build skills #

  • Search first. Look for the names the specification implies and for existing UC-XXX references.
  • Edit in place. Never create a second view, endpoint, service, repository, or DTO for the same use case.
  • Follow the diff. When a specification diff is passed, work through it change by change. A removed line means the behaviour it described must be deleted.
  • Keep the markers in step. Update a BR marker whose rule changed and remove it together with the code of a dropped rule.
  • Touch nothing else. No incidental refactoring, renaming, or restyling.
  • Report. List which files changed and which specification change drove each one.

Test skills #

  • Search first. Find the existing tests of the use case by the test markers in the Markers table.
  • Update, don't duplicate. Extend the existing class; never write a second test class for the same use case.
  • Mirror the specification. Add tests for new flows and rules, update changed ones, delete tests for behaviour the specification dropped.
  • Keep what still holds. Leave passing tests the specification still requires untouched, and update the test data when the data requirements changed.
  • Wait for lazy data. A browser test waits until a lazily loaded grid or list has fetched its rows after each navigation before it reads a cell or counts rows; lookups that do not retry otherwise see an empty list.
  • Run the class. Run the whole test class afterwards, not only the new tests.
Why it matters. A parallel implementation is the most expensive failure mode of AI-generated code: two views for one use case, only one of them tested. The coverage audit reports it as drift, but the build skill should never produce it in the first place.
Build it

Package and publish #

A layer plugin is a folder of skills with its manifests. Start by copying the layer plugin closest to yours and replace the technology, not the structure.

  1. Lay out the plugin #

    aiup-<technology>/
      .claude-plugin/plugin.json  # Claude Code manifest: name, description, version, author
      .tessl-plugin/plugin.json  # Tessl manifest
      plugin.json, mcp.json  # Agent Plugins manifest and MCP config
      .mcp.json  # documentation servers for your technology
      rules/mcp-servers.md  # how to configure those servers by hand
      skills/<technology>-<layer>/SKILL.md
      skills/<technology>-<layer>/references/layer.md
      skills/<technology>-<layer>/references/markers.md
      skills/<technology>-<layer>-test/SKILL.md
      skills/<technology>-<layer>-test/references/markers.md
      evals/  # scenarios that exercise the skills
  2. Write each skill #

    Each SKILL.md starts with a name that matches its folder and a description that lists the phrases that should trigger it ("write the jOOQ repository", the name of your framework) and says it is normally run by /use-case-implement or /use-case-test. Hosts such as Tessl install skills one folder at a time, so a skill links only to files inside its own folder, names another skill by slash command, and finds a file of another skill with a glob. A skill folder holds only .md and .py files; wrap an example class in Markdown, as aiup-jooq does with its test template.

  3. Connect documentation servers #

    Model training data lags behind framework releases. Declare MCP servers for your framework's documentation in .mcp.json and tell the skills to consult them when configured, and to fall back to their own documentation links otherwise. Tessl does not ship MCP server definitions, so rules/mcp-servers.md explains how to add them by hand.

  4. Support other AI coding tools #

    To run in Codex CLI, Cursor, GitHub Copilot, Gemini CLI, and OpenCode as well, add the Agent Plugins manifest (plugin.json and mcp.json at the plugin root) and the Tessl manifest, and bump all three versions together. See other AI coding tools.

  5. Contribute it #

    A layer plugin in your own repository works as it is: /stack finds it by its references/layer.md, without a change to aiup-core, and so does a skill in the project's skill folder or in ~/.claude/skills/. A Claude Code marketplace is just a Git repository with a marketplace.json. To make it available to every team, open a pull request against the marketplace repository: there the plugin also adds its row to the Plugins table of the layer catalog in aiup-core, and the CI checks keep that table, the layer.md files, and the @UseCase shape in step.

The other shape

Combined stack plugins #

A combined stack plugin builds UI, backend, and data access in one /implement. It fits an architecture that does not split into horizontal layers, such as vertical slices. It does not read the stack file and is not driven by /use-case-implement; it ships its own commands, and a project installs aiup-core plus exactly that one plugin.

aiup-blazor-dotnetStays combined for good: Vertical Slice Architecture. /ef-migration, /implement, /dotnet-test, /bunit-test, /playwright-test
aiup-nestjs-nextjsDeprecated, superseded by the layer plugins aiup-drizzle, aiup-nestjs, and aiup-nextjs, removed with aiup-core 4.0.0
aiup-vaadin-jooqDeprecated, superseded by the layer plugins, removed with aiup-core 4.0.0
aiup-angular-jpaDeprecated, superseded by the layer plugins, removed with aiup-core 4.0.0
  1. Migration #

    Required. Named after the migration tool: /ef-migration, /drizzle-migration.

    Reads the entity model and the existing migrations and writes the next versioned migration. A schema change is always a new migration; an applied one is never edited.

  2. Implement #

    Required. Always called /implement.

    Reads the same inputs as /use-case-implement and writes the complete slice of one use case, with the UC-XXX BR-YYY markers, reconciling existing code by the rules above. It writes no tests and ends by naming the next command.

  3. Unit and integration tests #

    Required. Named after the test tool: /dotnet-test, /bunit-test, /nest-test, /react-test.

    One test class or file per use case, covering the specification rather than the code, with the test markers above.

  4. End-to-end tests #

    Required. Always called /playwright-test.

    With a use case ID it drives the running application through that use case's scenarios; with a test case ID it writes one journey test with one step per Flow row.

  5. Coverage audit #

    Recommended. /coverage-check plus a read-only agent with this stack's markers.

    /use-case-coverage in aiup-core reads its markers from the stack file, which a combined plugin does not write. A combined plugin that wants the audit therefore ships its own copy of the agent, restricted to Read, Grep, and Glob, as aiup-vaadin-jooq and aiup-angular-jpa do.

Before you ship

Checklist #

Install your layer plugin next to aiup-core and the other layers of a small sample project, then check each point.

Discovered

Installed where the host finds it and enabled, /stack finds your skills by their references/layer.md, detects the technology from the source tree, and writes them into the Layers table.

Handed over

/use-case-implement UC-001 runs your build skill in its place, and the layer above builds on its Handover without a second DTO.

Markers recorded

After the first run, your rows are in the Markers table, and /use-case-coverage UC-001 finds your code and tests by them.

Tested once

/use-case-test UC-001 tests the use case in the integration layer, and a lower layer writes only tests of logic of its own.

Every test traced

Each test names its use case ID, scenario, and business rules, matching the specification's headings exactly.

Second run is a no-op

Running /use-case-implement twice on an unchanged specification changes nothing and creates no new files; after editing one alternative flow, only that flow's code and tests change.

Next step

Bring your stack to the AI Unified Process #

AI Unified Process Studio writes the specifications your layer plugin reads. Request an invitation, or get in touch if you want help designing a plugin for your architecture.