Skip to main content

Build a Feature with an AI Assistant

Overview​

Build one feature by specifying its business rules, representing accepted changes as events, and verifying its state transitions before connecting the UI. Mississippi gives both you and an AI assistant named places for each part of that work: commands, handlers, events, reducers, projections, actions, and effects.

This workflow uses Spring's bank-account withdrawal as a concrete reference. The business benefit is a reviewable path from a requirement to observable behavior: a reviewer can inspect the rule, the accepted event, and the resulting state separately.

When to use this​

Use this procedure when you want an AI assistant to implement one business operation with explicit source references and acceptance checks.

Before you begin​

  • Choose the capability and packages from the capability map.
  • Have an application following the Spring project boundaries, or use Spring to learn the workflow.
  • Give the assistant access to the source and tests for the framework version your application uses.
  • Read the write model so commands, events, and reducers have distinct responsibilities.

Steps​

1. Specify One Business Decision​

Write the rule and examples before requesting code. For a withdrawal, identify the account, the requested amount, the conditions for acceptance, and the state the user should eventually see.

Spring's WithdrawFundsHandler accepts a positive amount when the account is open and the balance is sufficient. The following cases translate those rules into observable outcomes; amounts are illustrative.

GivenWhenExpected outcome
Open account with balance 100Withdraw 25One FundsWithdrawn event for 25; reduced balance 75
Open account with balance 100Withdraw 100One FundsWithdrawn event for 100; reduced balance 0
Open account with balance 100Withdraw 101Rejection; no withdrawal event
Open account with balance 100Withdraw 0Rejection with InvalidCommand; no withdrawal event
Closed accountWithdraw 25Rejection with InvalidState; no withdrawal event

Use explicit outcomes such as these instead of a request like "make withdrawals work." They give the assistant a target that tests can check.

The current Spring handler reports InvalidCommand for insufficient funds. For a new handler, follow the repository's domain-modeling guidance: a valid command rejected by aggregate state returns InvalidState. The case above checks rejection and absence of an event without prescribing an error code.

2. Assign Each Concern to Its Artifact​

Keep the same vocabulary in the requirement, code, and tests.

ConcernArtifactSpring reference
Requested business operationCommandWithdrawFunds
State needed to decideAggregate stateBankAccountAggregate
Whether the request is validCommand handlerWithdrawFundsHandler
Accepted business factEventFundsWithdrawn
How the fact changes stateEvent reducerFundsWithdrawnReducer
Data the screen readsUX projectionBankAccountBalance

The handler returns an operation result containing emitted events or a failure. For a successful result, the aggregate runtime persists any emitted events before dispatching effects; a failed result returns without persisting events. The reducer applies a recorded fact to state. This separation lets you change how a screen displays a withdrawal while keeping the business decision in one place.

3. Provide a Bounded Implementation Brief​

Give the assistant a brief that names the artifacts, references, and acceptance tests. The following is a prompt template; replace the bracketed values with your application's details.

Implement [one business operation] using Mississippi [installed version].

Business rule:
[State required, accepted inputs, rejected inputs, and business outcome.]

Acceptance cases:
[Given state -> command -> event or rejection -> resulting state.]

Interface access:
[Authentication mechanism, permitted callers, and operation/entity permissions.]
[The application boundary that checks the requested entity ID.]

Use these references:
[Paths to the existing aggregate, handler, event, reducer, and tests.]
[Relevant Mississippi documentation and source for the installed version.]

Deliver:
- A named command expressing business intent.
- A handler that validates the request against aggregate state.
- Events representing accepted facts and pure reducers applying them.
- Tests for acceptance, rejection, boundaries, and state transitions.
- Generated integration through the supported Inlet attributes.
- Authentication and authorization for exposed APIs and subscriptions.
- Interface tests for anonymous callers, insufficient permissions, and denied entities.
- The projection and client changes needed to observe the result.

Before editing, identify the files and verification steps.
For each API or behavior, check the supplied source and existing tests.
Report executed checks and the behavior each check verifies.

Keep the task to one operation at a time. Review the resulting domain diff before asking for another feature. The template guides implementation; the acceptance tests provide evidence for whether the result is correct.

4. Keep Deterministic Transitions Explicit​

For deterministic state reconstruction, implement a reducer as a pure function from prior state and its event or action to the next state. With the same recorded inputs and reducer implementation, it produces the same state. Put externally obtained facts into the event or action before reduction so replay uses the recorded inputs.

For example, Spring's withdrawal reducer subtracts the event amount and increments the withdrawal count. The reducer has everything needed to explain that transition. That makes it useful for debugging, testing, and asking an assistant to explain an unexpected balance.

Use these choices when reviewing generated suggestions:

PreferRework this suggestionReason
WithdrawFunds as a named commandA generic "set account state" requestThe handler can enforce the withdrawal's business rule
FundsWithdrawn as the accepted factPassing the command directly to an event reducerThe persisted history should represent accepted outcomes
A new state value computed from state and eventReading the clock or calling an API in the reducerRecorded inputs make state reconstruction repeatable
A focused projection for a screenReimplementing server balance rules in a componentThe screen can consume the read model built from accepted events
An effect for external workSending notifications from a reducerEffects give external work an explicit execution boundary

The server reducer contract is EventReducerBase. Reservoir uses its own action-reduction contracts for local feature state; see Reservoir reference.

5. Let Generators Connect the Domain​

After verifying the business behavior and defining interface access, follow the existing application's attributed domain pattern. Inlet generates the supported transport and client artifacts from those inputs. For example, Spring's WithdrawFunds declares a command route and BankAccountAggregate opts into aggregate endpoints.

For a network-accessible gateway, configure host authentication and authorization before mapping generated transports. Define the application policies and put [GenerateAuthorization] metadata on each protected generated command, projection, and saga. Verify every generated route's effective authorization.

Register the host's authentication scheme with AddAuthentication before using this configuration. Define the default application policy, then enable force mode through AddInletServer:

builder.Services.AddAuthorizationBuilder()
.AddPolicy("generated-api", policy => policy.RequireAuthenticatedUser());

builder.Services.AddInletServer(options =>
{
options.GeneratedApiAuthorization.Mode =
GeneratedApiAuthorizationMode.RequireAuthorizationForAllGeneratedEndpoints;
options.GeneratedApiAuthorization.DefaultPolicy = "generated-api";
options.GeneratedApiAuthorization.AllowAnonymousOptOut = false;
});

This mode configures generated HTTP API and projection-subscription authorization; it does not configure MCP authorization. In force mode, the convention adds a default HTTP authorization filter only when neither the generated controller nor any of its actions has an explicit [Authorize] or authorization filter. If any action has explicit authorization, the convention adds no default controller filter for its unannotated actions; explicitly authorize every action that must be protected. AllowAnonymousOptOut defaults to true, so generated [AllowAnonymous] metadata remains an opt-out in force mode; set it to false to remove that opt-out. GeneratedApiAuthorization.Mode defaults to Disabled. Review the authorization options and generation metadata explicitly.

Generated API authorization applies to generated HTTP controllers and Inlet projection subscriptions; it does not authorize MCP. Generated MCP tool methods call aggregate, saga, and UX projection grains directly, so protect the MCP host or route with the application's MCP authorization boundary before exposing those tools. Spring registers generated MCP tools but maps /mcp only when the host environment is Development (Spring.Gateway/Program.cs). Include separate MCP access checks when exposing that transport.

Treat permission to act on a particular entity as an application decision. Inlet's generated projection-subscription authorization passes null as the ASP.NET authorization resource; it does not supply entityId for resource-based policy evaluation. Name the application boundary that receives the entity ID and verifies access, and include that decision and its tests in the implementation brief.

Use the generated artifacts as part of the application's build. Keep the human-authored rule in the handler and the state transition in the reducer. When reviewing assistant changes, check the domain attributes and the resulting API/client behavior together.

Continue through adding an aggregate command, building projections, and client composition for the concrete integration paths.

Verify the result​

Use more than successful compilation to judge completion.

  1. Run handler tests covering the acceptance matrix, including rejection codes and emitted event data.

  2. Run reducer tests checking the next state and preservation of the input state.

  3. Verify generated registrations and compile the runtime, gateway, and client projects that consume the domain.

  4. Exercise the command through the application and observe the projection and subscribed client state.

  5. Check command progress and projection progress as separate observations. The client synchronization model delivers projection changes asynchronously.

  6. For exposed interfaces, verify anonymous requests are rejected (401/403 as appropriate), authenticated callers without permission are denied, and the application rejects access to unauthorized entities. Check allowed and denied projection subscriptions too. Spring auth-proof mode supplies executable HTTP authorization cases with development identities. Add application-specific SignalR integration checks for allowed and denied subscriptions.

Run the Spring Checks​

For the Spring example, run the domain tests from the repository root with PowerShell 7 and the .NET SDK selected by global.json. The canonical quality script builds the test project and its dependencies, executes the tests, and writes TRX and coverage evidence.

pwsh ./eng/src/agent-scripts/test-project-quality.ps1 -TestProject samples/Spring/Spring.Domain.L0Tests/Spring.Domain.L0Tests.csproj -SourceProject samples/Spring/Spring.Domain/Spring.Domain.csproj -SkipMutation

Require exit code 0, RESULT: PASS, a nonzero TEST_TOTAL, and matching TEST_PASSED and TEST_TOTAL. Inspect the emitted test_results.trx path for the individual handler and reducer results. -SkipMutation selects the ordinary test-and-coverage check.

Build the consuming sample projects with the canonical sample build entry point:

pwsh ./build.ps1 -SkipMississippi -Configuration Release

This builds samples.slnx, including Spring's runtime, gateway, client, and their referenced projects. Require exit code 0 and ALL REQUESTED BUILDS COMPLETED SUCCESSFULLY, with zero build warnings and errors. The build checks generated integration; the tests above check business behavior.

For another Mississippi repository sample, substitute its actual test and source project paths in the quality command. In your own application, use your solution's build/test entry points and apply the same acceptance cases and nonempty test-result checks; these PowerShell scripts belong to the Mississippi repository.

Spring provides withdrawal handler tests and withdrawal reducer tests as concrete examples. Its repository validation guide explains the executable API and browser checks.

Summary​

Give an AI assistant explicit business intent, concrete source references, and observable acceptance cases. Use Mississippi's handlers and reducers to keep decisions and transitions reviewable, generators to connect the supported interfaces, and tests to verify the delivered behavior.

Next Steps​