Spec-driven development

Spec-Driven Development is a natural evolution of prompting AI assistants to generate code. It treats specifications as actionable, executable documents. These documents are the only source of truth, the code is entirely AI-generated, and divergence from the specification can be automatically detected and used to fail builds in an automated CI pipeline.

AI assistance maturity levels

It may help to think of the steps in this evolution as different levels in a maturity model for AI-assisted development. For some of us these levels are chronological but others may have jumped directly into later levels. There is no objectively right or wrong level, but we’re focused on the highest maturity level in this document.

Direct prompting

With direct prompting, you supply prompts to your favorite AI assistant and get generated code back. This can be useful for demonstrations and sample applications, but this level has no reliable source of truth. AI assistants are well known for producing different output for the same prompt. Attempts to move toward a reliable source of truth and decrease the random nature of the output lead to the next maturity level.

Single-file specification

While code assistant chat logs can be saved and exported, they’re unsuitable for use as a source of truth, a specification, or a document that can be committed to version control. The next evolution is typically when people create a single specification file in markdown. This file contains the entirety of an application specification, including the details on what is being built, why it is being built, and how it should be built (tech specifications).

This maturity level has a single source of truth (the spec file) which can be version controlled. More importantly, LLMs can be used to judge how well the generated code conforms to the specification. Deviations above a certain threshold can be used to fail builds and trigger human-in-the-loop workflows that may result in many iterations refining the specification.

Crucially, this single file specification is usually written mostly by humans. This becomes unwieldy once a specification reaches a certain level of complexity.

Formal spec-driven process

A single SPEC.md or specification.md file may be enough for some projects. Many sample or demonstration applications can be built properly with just a single file. However, when our needs and complexity reach a certain point, we need a formal process. This process is iterative, git-friendly, and enlists the aid of the AI assistant both in building the spec and generating the code from it. It addresses the need to build formal specifications that are consumable by both human and AI alike while reducing random and unexpected output. This process is covered in detail in this document.

Using Akka specify

Akka makes it incredibly easy to get started with a new Spec-Driven project. Instead of using akka code init, use the newer akka specify init command. This will give you everything you need to kick off your Spec-Driven development cycle.

Please refer to Install the Akka CLI for installation instructions.

At the moment the only supported assistant is Claude Code, but support for other assistants is coming soon. For other agents, you can manually add Akka as an MCP server using the _mcp.json file that comes with the new project template.

Initialization and constitution adoption

Running akka specify init will populate a project directory with an empty Akka project. In addition, it grabs all of the markdown templates necessary for the spec-driven process. Once you’ve run this command, change to the directory of your new project (if you’re not already there) and launch your favorite code assistant.

One of the important files that comes with your new project is a constitution. The constitution.md file is where unbreakable rules for the entire project are defined. This file contains mandates about technology requirements, design rules, and more. Akka will give you a default constitution that contains all of the mandatory requirements for Akka applications. In addition to the Akka-specific constitution, the initialization process lets you add an additional layer of constitution. You can use this to include mandates from your company, organization, team, etc. It then becomes easy to maintain your own constitution while still benefiting from Akka’s rules.

The constitution is typically defined once at the start of a project and only refined as necessary. Constitution amendments are considered one-off exceptions and not as part of the core development loop.

Specify a feature

It’s possible to specify an entire application by supplying a prompt to the /akka.specify agent command, but it isn’t recommended. If your application is simple enough that it can be specified in a single prompt or file, you should use a single-file spec as the full spec-driven process is likely overkill for your needs.

To specify a new feature, use the following syntax from inside your AI agent:

/akka.specify {feature short description} - {feature specification prompt}

The short description of the feature will be turned into a branch name like 00#-feature-short-description where the description you supply is turned into kebab case. This will also be the name of the new git branch created.

The prompt for the feature specification should exclusively define the what and why of the feature, and should not contain any technical implementation details. In the sample prompt below for a chess application core website, we mention that it doesn’t use federated authentication. While this seems like a how level (plan) declaration, it does belong at the higher specification level because the concept of federation is a high level specification and we don’t mention how federation should be coded.

Prompt 1. Chess core site feature

/akka.specify core users - The chess application manages its own users. It does not integrate with federation technologies like OAuth. Users are uniquely identified by a username and they authenticate via password. Users can edit their profile and supply a friendly name and upload a small avatar image. Email verification is not used. Users can delete their own accounts. Users can view the profile of other users, but anonymous (not logged in) users cannot see any data.

This creates a new specification in the specs/001-core-users directory, in the 001-core-users branch. At this stage, resist the temptation to go and manually edit the spec. Clarification is the next step.

There’s no mention in this prompt of services or UI applications or how a web application is supposed to be served. We recommend that you keep your feature specifications scoped to something small enough where you have a clear idea of the acceptance criteria and the generated code won’t be so large that it can’t easily be reviewed by humans or AI. Opinions vary on the scope of a "feature" so this is something teams generally decide amongst themselves and often on a per-feature basis.

Clarify the specification

Clarification is a critical step in this process. You start it by using a single command with no parameters:

/akka.clarify

Your AI assistant will then analyze your constitution, your feature specification, and any conversation history you have built up and identify gaps. It looks for places where it would have to make a decision and it doesn’t already have enough information to make that decision. If you run akka.clarify on the chess core users feature, you will likely be asked several questions.

When we run it, we typically get asked to clarify how users are uniquely identified (internal UUID or username). We also get asked what happens to deleted users and whether users can have multiple concurrent sessions in the application from multiple devices. Achieving this level of clarity is a hallmark of spec-driven development that we rarely get with single-file specs or even less formal multi-file specifications.

Once your AI assistant can no longer detect any more necessary clarifications, it’s time to define the implementation plan.

Define the implementation plan

The implementation plan is your technical architecture and technical design. Here you specify the how of your application. While it’s a popular notion that anyone can build a spec-driven application, this isn’t entirely accurate. You need to be able to decide how you want your application to be built, and you need to know how to describe that in natural language clear enough for an LLM to understand it.

If you get all the way to code generation for the feature and you didn’t get what you wanted, then you may need to iterate on the implementation plan. Amendments to the plan are tracked diligently along with constitution and feature updates.

It is worth remembering that, like the specify step, the input to the plan step is a prompt, it is not the full and final plan. That is output by your agent.

Take a look at this sample plan prompt for the chess game sample first feature.

Prompt 2. Chess feature implementation plan

/akka.plan The implementation is an Akka service with both a static asset website user experience and the supporting RESTful API. The website uses simple JavaScript and not large frameworks like React. These assets are exposed via an HTTP endpoint with the resources in src/main/resources and served statically.

The website has a clean, professional look and uses tailwind CSS. The application logo should be a simple dark blue king chess piece. It should have a navigation bar on the top with access to login/logout/profile via a menu option in the top right of the nav.

The RESTful API is exposed via a separate HTTP endpoint. This API requires authentication for all operations except login. The authn/authz for these HTTP routes can be HTTP Basic and does not need to be anything more complex. Active user sessions are maintained via Key Value entities and are created upon login. This implies that a user will have a different session when logged in on a different device. A TimedAction is responsible for deleting sessions for users that have not submitted an API request after some timeout period. The RESTful API routes all start with a common api/v1 prefix while the static UI assets use the root prefix and if no resource is specified on the URL then the index.html static resource file will be used. This page should be an empty placeholder for now, containing just a placeholder text and the top navigation bar.

The static assets will refer to the API via a full URL. This URL defaults to localhost on the current port, but can be overridden via the CHESS_API_URL environment variable available when running the service.

There is a balance between including something in your specification prompt and assuming that your AI assistant will infer other important items that need to be in the final plan. It is common to spend extra time iterating on the plan prompt to make sure that the plan output is correct. Thankfully the plan output is categorized by priority and functional requirements, making it easy to verify.

In other words: make sure you agree with the functional requirements before continuing on to the next step. If you want to add requirements to the plan, you can do so interactively with your agent and it will update the plan accordingly.

Generate a task list

The next step toward a running feature is to generate a task list with /akka.tasks. This will take your clarified specification and your implementation plan and convert that into a formal set of work items. Your agent should identify which tasks should be done first and which ones can be done in parallel. If you’re satisfied with the set of tasks generated, then you can continue to the next step.

You can also provide updates to the task list here by discussing it with your agent.

Implement the code

It’s finally time to have your assistant write the code. When you use the /akka.implement command in your chat prompt, it will create your application code. Make sure that before you run this command, you’re satisfied with the level of effort or "thought" being used by your agent. The results can vary drastically between medium and high effort levels.

During this step, it is common to see the agent make mistakes, generate compilation failures, and produce test failures. This is normal and the agent should be iterating toward the right answer. Only stop the agent in the middle of this step if you see something drastically wrong or you see the agent diverging from the solution over time instead of converging.

The default Akka constitution mandates both unit and integration tests, so these should also be generated and verified during this step.

When the code is complete, you should be able to exercise any RESTful APIs or user interfaces created. Akka actually makes this step easier as well.

Build, exercise, and deploy

You should never have to leave your agent chat during the spec-driven SDLC. If you use the /akka.build command, you will get a ton of extra bonus features beyond a simple mvn compile exec:java.

  • Pre-existing services will be shut down

  • Anything using the target port will be shut down

  • Your service is re-compiled and all tests are run

  • Your service is launched

  • Your service will be exercised through the real endpoints to verify functionality. This is like building and exercising a custom Postman script or writing and using your own shell script, except its easier and automated.

  • The build command leaves your service running, so you can exercise it manually, including using the Akka console’s built-in request tracking.

  • If you make changes to any of the documents, either from within or without your agent chat, your service will be recompiled and automatically restarted

If you want to deploy your service to Akka’s infrastructure through Akka Automated Operations, you can simply use the /akka.deploy command. This command will prompt you for the organization and project into which you want to deploy. It then seamlessly deploys your service, automatically doing a rolling update of the service cluster if one is already running.

Specify your ideas!

The greatest barrier to building new things is rarely the idea. It’s usually in the implementation. Spec-Driven Development frees you from this barrier, letting you turn your ideas into specification and plan prompts, and watching as Claude (or whatever agent you’re using) generates and populates a to-do list and implements all of the code for you.

You no longer have to invest massive amounts of time in "what-if" scenarios, you can just specify and go. All you need is initspecifyclarifyplantasksimplement and build.

Using SDD with careful feature scoping and concise technical implementation plans, you’re never more than a matter of minutes from a feature you can interact with. With Akka, you know those features will automatically be powerful, resilient, scalable distributed systems.

SDD commands in your coding assistant

/akka.specify

Supply a prompt to produce your feature spec

/akka.clarify

Find gaps in your spec

/akka.plan

Convert your spec into a technical implementation plan

/akka.tasks

Itemize the work required to build according to the spec

/akka.implement

Generate the required code, tests, harnesses, etc.

/akka.build

Build, test, and run locally with hot reloading

/akka.deploy

Deploy to Akka Automated Operations

References