diff --git a/CLAUDE.md b/CLAUDE.md index 66b19d8..f981e52 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -89,7 +89,11 @@ Each file in `claude/commands/{name}.md` is a tiny wrapper that points at `.awos ## Architecture: Document-Centric Workflow -AWOS is **spec-driven** — all project state lives in markdown files under `context/` in the user's project, not in chat history. An AI agent can rehydrate full context by reading the files alone. The canonical flow (each command is a markdown prompt under `commands/`): +AWOS is **spec-driven** — all project state lives in markdown files under `context/` in the user's project, not in chat history. An AI agent can rehydrate full context by reading the files alone. + +**Brownfield projects** get automatic codebase awareness. `/awos:product` detects existing source code (during Creation Mode only) and creates `context/product/brownfield.md` with triaged findings about purpose, audience, and features. `/awos:roadmap` and `/awos:architecture` read that file and run their own focused explorations (capabilities and tech stack respectively), passing prior findings to avoid duplicate questions. All findings are triaged with the user (accept / correct / reject). `/awos:architecture` removes the file after all knowledge is absorbed into the product, roadmap, and architecture documents. + +The canonical flow (each command is a markdown prompt under `commands/`): ``` /awos:product → /awos:roadmap → /awos:architecture → /awos:hire diff --git a/README.md b/README.md index 4bf1391..9106cbe 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ npx @provectusinc/awos This sets up the `.awos/` directory (commands, templates, scripts), the `.claude/commands/awos/` wrappers, and the `context/` directory where your project documents will live. It also registers the AWOS plugin marketplace in your project settings. > **Running on an existing codebase?** Start with an AI readiness audit to understand how AI-friendly your project is. Install the plugin with `/plugin install awos@awos-marketplace`, then run `/awos:ai-readiness-audit` to get a scored assessment with actionable recommendations for improvement. [Learn more](plugins/awos/README.md) +> +> AWOS integrates seamlessly with existing projects — the setup commands auto-detect your codebase and use it as context, so you won't start from a blank slate. ### Step 2: Foundation Setup diff --git a/commands/architecture.md b/commands/architecture.md index 73cea4f..284ba22 100644 --- a/commands/architecture.md +++ b/commands/architecture.md @@ -19,6 +19,7 @@ Your task is to manage the architecture file located at `context/product/archite - **Template File:** `.awos/templates/architecture-template.md` (The required structure). - **Prerequisite Input 1:** `context/product/product-definition.md` (The "what" and "why"). - **Prerequisite Input 2:** `context/product/roadmap.md` (The implementation phases). +- **Optional Input:** `context/product/brownfield.md` (produced by `/awos:product`, extended by `/awos:roadmap`; deleted at end of this command). - **Primary Input/Output:** `context/product/architecture.md` (The file to create or update). --- @@ -49,12 +50,42 @@ Follow this logic precisely. ## Scenario 1: Creation Mode 1. Read and synthesize the product definition and roadmap, paying close attention to features planned for Phase 1. -2. Work through the template section by section — not all at once. +2. **Brownfield context.** Check if `context/product/brownfield.md` exists (produced by `/awos:product` when it detects an existing codebase). If it does: + + a. Read `context/product/brownfield.md`. + + b. Construct the Explore prompt by reading `context/product/brownfield.md` and embedding its full content between `` and `` tags. Then launch an `Explore` agent focused on the technology stack: + + ```text + Agent(subagent_type="Explore", description="Discover existing tech stack", prompt=" + Explore this codebase and document the existing technology stack. Focus on: + - Languages and frameworks (with versions from config files) + - Databases, ORMs, and data stores + - Infrastructure (Docker, cloud configs, deployment scripts) + - External services and APIs (auth providers, payment, analytics) + - Testing frameworks and tools + - Build tools, bundlers, CI/CD + + The following findings were already confirmed by the user — do not repeat them: + + + {paste the full current contents of context/product/brownfield.md here} + + + Report only NEW findings not covered above. For each technology found, cite the file paths that evidence it. Be concise — report findings as bullet points. + ") + ``` + + c. Triage new findings with the user. Group related findings by category and use `AskUserQuestion` to batch up to four per call. For each finding, offer **Accept** and **Reject** as options. The user can also select "Other" to provide free-text feedback — treat it according to intent (correction, substitution, partial accept, or any other reaction). Discard rejected findings. Append accepted and corrected findings to `context/product/brownfield.md` under a `## Technology` heading. For corrected findings, record the corrected version, not the original. + + d. Use the confirmed technology findings as the default for each section, but still walk every section with the user. The interview still covers every area; the exploration gives better defaults, not fewer questions. + +3. Work through the template section by section — not all at once. - For each architectural area, propose a concrete title from the template placeholder. - - For each component, propose a specific technology with one or more alternatives, justified by the project context. + - For each component, propose a specific technology with one or more alternatives, justified by the project context. When brownfield findings provided a known technology, present it as the default. - If the user is unsure, ask clarifying questions about team skills, budget, or priorities. Do not proceed until the current section is confirmed. - Repeat for every architectural area (Data, Infrastructure, etc.). -3. Once all sections are confirmed, proceed to **Step 3: Finalization**. +4. Once all sections are confirmed, proceed to **Step 3: Finalization**. --- @@ -84,3 +115,9 @@ Give the user a quick read on whether the stack already has specialist agents 3. Report the saved path and the next commands: - `/awos:hire` (always — it owns the canonical coverage report and installs missing specialists). - `/awos:spec` after `/awos:hire`. + +--- + +### Step 5: Brownfield Cleanup + +If `context/product/brownfield.md` exists, delete it. By this point all brownfield knowledge has been absorbed into `product-definition.md`, `roadmap.md`, and `architecture.md` — the brownfield file is no longer needed. diff --git a/commands/product.md b/commands/product.md index 101fc7f..55eb5ae 100644 --- a/commands/product.md +++ b/commands/product.md @@ -30,6 +30,7 @@ Your primary task is to **fill in** a product definition template using a guided # OUTPUTS 1. **`context/product/product-definition.md`:** The complete, non-technical product definition, created by filling in the template. +2. **Optional Output:** `context/product/brownfield.md`. Created on brownfield projects only. Downstream commands (`/awos:roadmap`, `/awos:architecture`) extend and eventually delete this file. --- @@ -62,14 +63,34 @@ First, check if the file `context/product/product-definition.md` exists. ### Step 2B: Creation Mode -1. If `` is non-empty, briefly note that you'll use it as a starting point, then refine from there. -2. Walk the user through the sections of the template, explaining each one. +1. **Brownfield detection.** Check whether the project already has source code by looking for common indicators (`src/`, `app/`, `lib/`, `package.json`, `requirements.txt`, `go.mod`, `Cargo.toml`, `pom.xml`, `Gemfile`, `build.gradle`, `*.csproj`, `Makefile`, `CMakeLists.txt`, `setup.py`, `pyproject.toml`, or similar). If any are found, ask the user whether to run codebase exploration using `AskUserQuestion` with two options: **Yes, explore the codebase** ("Use existing code as context for the product definition") and **No, start from scratch** ("Treat this as a new project — ignore existing code"). If the user chooses to skip, proceed to step 2 as if no source code was found. Otherwise, run a comprehensive exploration before starting the interview: + + a. Launch an `Explore` agent focused on the product domain: + + ```text + Agent(subagent_type="Explore", description="Understand existing product", prompt=" + Explore this codebase and determine what this project does. Focus on: + - Purpose and problem being solved (README, docs, package metadata, comments) + - Target audience signals (UI copy, API design, documentation tone, onboarding flow) + - Main features and capabilities (entry points, routes, commands, key modules) + - User journey (how someone uses this from start to finish) + + For each finding, cite the file paths that evidence it. Be concise — report findings as bullet points. + ") + ``` + + b. Triage findings with the user. Group related findings by category (e.g. all features in one call, audience signals in another) and use `AskUserQuestion` to batch up to four per call. For each finding, offer **Accept** and **Reject** as options. The user can also select "Other" to provide free-text feedback — treat it according to intent (correction, substitution, partial accept, or any other reaction). Discard rejected findings. + + c. Create `context/product/brownfield.md` with a `## Product` heading. List all accepted and corrected findings under it — for corrected findings, record the corrected version, not the original. If every finding was rejected or the exploration surfaced nothing, still create the file with an empty `## Product` section; downstream commands (`/awos:roadmap`, `/awos:architecture`) key on the file's existence to run their own explorations. + +2. If `` is non-empty, briefly note that you'll use it as a starting point, then refine from there. +3. Walk the user through the sections of the template. When step 1 produced brownfield findings, use the Product section to propose draft answers — frame questions as "does this match what you intend, or would you change it?" rather than asking from a blank slate. The interview still covers every section; the exploration gives better defaults, not fewer questions. - **Project Name & Vision:** Ask for the project's name and its core purpose. - **Target Audience & Personas:** Ask who the product is for and help create one simple persona. - **Success Metrics:** Ask how they will measure the product's impact on the user. - **Core Features & User Journey:** Ask for the 3-5 most important high-level features and a simple user workflow. - **Project Boundaries:** Ask what is essential for the first version (In-Scope) and what can wait (Out-of-Scope). -3. Once all sections are complete, proceed to **Step 3: File Generation**. +4. Once all sections are complete, proceed to **Step 3: File Generation**. --- diff --git a/commands/roadmap.md b/commands/roadmap.md index 1bdadab..65bd3df 100644 --- a/commands/roadmap.md +++ b/commands/roadmap.md @@ -21,6 +21,7 @@ Your task is to manage the product roadmap file located at `context/product/road - **Template File:** `.awos/templates/roadmap-template.md`. This is the required structure for the roadmap. - **Prerequisite Input:** `context/product/product-definition.md`. This file MUST exist. +- **Optional Input/Output:** `context/product/brownfield.md` (produced by `/awos:product` on brownfield projects; this command appends a `## Capabilities` section). - **Primary Input/Output:** `context/product/roadmap.md`. This is the file you will create or update. --- @@ -51,9 +52,36 @@ Follow this logic precisely. ## Scenario 1: Creation Mode 1. Read `context/product/product-definition.md` and the template at `.awos/templates/roadmap-template.md`. -2. Generate a proposed roadmap by populating the template structure with the product definition's Core Features, grouped into logical sequential phases. -3. Present the full draft to the user and ask for feedback. -4. Iterate until the user is satisfied, then proceed to **Step 3: Finalization**. +2. **Brownfield context.** Check if `context/product/brownfield.md` exists (produced by `/awos:product` when it detects an existing codebase). If it does: + + a. Read `context/product/brownfield.md`. + + b. Construct the Explore prompt by reading `context/product/brownfield.md` and embedding its full content between `` and `` tags. Then launch an `Explore` agent focused on existing capabilities: + + ```text + Agent(subagent_type="Explore", description="Assess existing capabilities", prompt=" + Explore this codebase and assess what's already built. Focus on: + - Features that are fully implemented and working (with evidence: routes, UI, tests) + - Features that appear partially implemented or scaffolded + - TODOs, FIXMEs, or planned features mentioned in code or docs + + The following findings were already confirmed by the user — do not repeat them: + + + {paste the full current contents of context/product/brownfield.md here} + + + Report only NEW findings not covered above. For each finding, cite the file paths that evidence it. Be concise — report findings as bullet points. + ") + ``` + + c. Triage new findings with the user. Group related findings by category and use `AskUserQuestion` to batch up to four per call. For each finding, offer **Accept** and **Reject** as options. The user can also select "Other" to provide free-text feedback — treat it according to intent (correction, substitution, partial accept, or any other reaction). Discard rejected findings. Append accepted and corrected findings to `context/product/brownfield.md` under a `## Capabilities` heading. For corrected findings, record the corrected version, not the original. + + d. Use the full set of confirmed capabilities (from brownfield.md) to anchor the roadmap: existing capabilities are noted as already done, and new phases focus on what comes next. Feed this into the roadmap generation in the next step. + +3. Generate a proposed roadmap by populating the template structure with the product definition's Core Features, grouped into logical sequential phases. +4. Present the full draft to the user and ask for feedback. +5. Iterate until the user is satisfied, then proceed to **Step 3: Finalization**. --- diff --git a/tests/lint-prompts.test.js b/tests/lint-prompts.test.js index e658340..3539859 100644 --- a/tests/lint-prompts.test.js +++ b/tests/lint-prompts.test.js @@ -657,6 +657,211 @@ test('SDD-07 recognizes the dual-model QA coverage', () => { ); }); +// --------------------------------------------------------------------------- +// Brownfield awareness contracts +// --------------------------------------------------------------------------- + +test('product.md creates context/product/brownfield.md on brownfield detection', () => { + // /awos:product is the entry point for brownfield detection. When it finds + // source code indicators it must explore the codebase and write accepted + // findings to context/product/brownfield.md. Downstream commands (roadmap, + // architecture) depend on this file existing to avoid duplicate exploration. + const body = readUtf8(path.join(commandsDir, 'product.md')); + assert.ok( + body.includes('context/product/brownfield.md'), + 'commands/product.md must reference context/product/brownfield.md as the brownfield findings destination' + ); + assert.ok( + /with a `## Product` heading/.test(body), + 'commands/product.md must write brownfield findings under a "## Product" heading (anchored to brownfield.md context)' + ); +}); + +test('product.md brownfield detection includes source code indicators', () => { + // The whole brownfield entry point depends on product.md checking for + // source code indicators. If the indicator list is hollowed out, + // brownfield never fires and the entire downstream chain goes dead. + const body = readUtf8(path.join(commandsDir, 'product.md')); + assert.ok( + body.includes('package.json'), + 'commands/product.md must check for package.json as a brownfield indicator' + ); + assert.ok( + body.includes('`src/`'), + 'commands/product.md must check for src/ as a brownfield indicator' + ); +}); + +test('roadmap.md reads brownfield.md and appends a Capabilities section', () => { + // /awos:roadmap reads the brownfield file produced by /awos:product and + // runs its own focused exploration for capabilities. It must append its + // findings under a "## Capabilities" heading so /awos:architecture can + // see the accumulated context. + const body = readUtf8(path.join(commandsDir, 'roadmap.md')); + assert.ok( + body.includes('context/product/brownfield.md'), + 'commands/roadmap.md must reference context/product/brownfield.md to consume and extend brownfield findings' + ); + assert.ok( + /under a `## Capabilities` heading/.test(body), + 'commands/roadmap.md must append brownfield findings under a "## Capabilities" heading (anchored to brownfield.md context)' + ); +}); + +test('architecture.md reads brownfield.md and appends a Technology section', () => { + // /awos:architecture reads the accumulated brownfield file and runs a + // focused exploration for the tech stack. It must append its findings + // under a "## Technology" heading. + const body = readUtf8(path.join(commandsDir, 'architecture.md')); + assert.ok( + body.includes('context/product/brownfield.md'), + 'commands/architecture.md must reference context/product/brownfield.md to consume and extend brownfield findings' + ); + assert.ok( + /under a `## Technology` heading/.test(body), + 'commands/architecture.md must append brownfield findings under a "## Technology" heading (anchored to brownfield.md context)' + ); +}); + +test('architecture.md conditionally removes brownfield.md after onboarding completes', () => { + // /awos:architecture is the last command that uses brownfield.md. By this + // point all brownfield knowledge has been absorbed into product-definition.md, + // roadmap.md, and architecture.md. The brownfield file must be conditionally + // cleaned up here, not deferred to /awos:hire. + const body = readUtf8(path.join(commandsDir, 'architecture.md')); + assert.ok( + /If `context\/product\/brownfield\.md` exists, delete it/i.test(body), + 'commands/architecture.md must conditionally delete context/product/brownfield.md (guard + delete in one sentence)' + ); +}); + +test('brownfield commands launch Explore agents', () => { + // The actual mechanism for brownfield awareness is the Explore agent. + // Without it, the headings and triage prose are dead letters. Assert + // that all three commands invoke the Explore subagent. + for (const cmd of ['product.md', 'roadmap.md', 'architecture.md']) { + const body = readUtf8(path.join(commandsDir, cmd)); + assert.ok( + /subagent_type="Explore"/.test(body), + `commands/${cmd} must launch an Explore agent for brownfield analysis` + ); + } +}); + +test('brownfield exploration passes existing findings to avoid duplicates', () => { + // Each downstream exploration (roadmap, architecture) must pass the + // current brownfield.md content to the Explore agent so it skips + // already-confirmed findings. The literal tag is + // the contract — if renamed, the Explore prompt silently ignores it. + // The "Report only NEW" instruction makes the tag actually work. + for (const cmd of ['roadmap.md', 'architecture.md']) { + const body = readUtf8(path.join(commandsDir, cmd)); + assert.ok( + body.includes(''), + `commands/${cmd} must pass existing brownfield findings inside tags to the Explore agent` + ); + assert.ok( + /Report only NEW/i.test(body), + `commands/${cmd} must instruct the Explore agent to report only NEW findings` + ); + } +}); + +test('product.md does not consume existing_findings (it is the first command)', () => { + // product.md is always first in the brownfield chain — it must not + // consume since there are none before it. If it + // gained that tag, it would imply a circular dependency. + const body = readUtf8(path.join(commandsDir, 'product.md')); + assert.ok( + !//.test(body), + 'commands/product.md must not contain — it is the first brownfield command' + ); +}); + +test('brownfield commands use accept/reject triage for findings', () => { + // All three brownfield-aware commands must triage findings with the + // user offering Accept and Reject options. The user can also provide + // free-text via the built-in "Other" field. + for (const cmd of ['product.md', 'roadmap.md', 'architecture.md']) { + const body = readUtf8(path.join(commandsDir, cmd)); + assert.ok( + /Accept/.test(body), + `commands/${cmd} must offer "Accept" as a triage option for brownfield findings` + ); + assert.ok( + /Reject/.test(body), + `commands/${cmd} must offer "Reject" as a triage option for brownfield findings` + ); + } +}); + +test('brownfield exploration includes fill-in slot for brownfield.md content', () => { + // The fill-in slot tells the agent to interpolate brownfield.md contents + // into the Explore prompt. Without it, is empty and + // dedup silently dies while the tag still matches. + for (const cmd of ['roadmap.md', 'architecture.md']) { + const body = readUtf8(path.join(commandsDir, cmd)); + assert.ok( + /\{paste the full current contents of context\/product\/brownfield\.md here\}/.test( + body + ), + `commands/${cmd} must include the fill-in slot for brownfield.md content interpolation` + ); + } +}); + +test('brownfield commands append (not overwrite) findings to brownfield.md', () => { + // Each downstream command must append to brownfield.md, not overwrite it. + // The append verb + heading together protect the accumulate-don't-overwrite + // contract. + const roadmapBody = readUtf8(path.join(commandsDir, 'roadmap.md')); + assert.ok( + /Append.*under a `## Capabilities` heading/i.test(roadmapBody), + 'commands/roadmap.md must append findings under a ## Capabilities heading' + ); + const archBody = readUtf8(path.join(commandsDir, 'architecture.md')); + assert.ok( + /Append.*under a `## Technology` heading/i.test(archBody), + 'commands/architecture.md must append findings under a ## Technology heading' + ); +}); + +test('brownfield commands guard exploration on brownfield.md existence', () => { + // Roadmap and architecture must check if brownfield.md exists before + // running their explorations. Without this guard, greenfield projects + // would attempt brownfield exploration. + for (const cmd of ['roadmap.md', 'architecture.md']) { + const body = readUtf8(path.join(commandsDir, cmd)); + assert.ok( + /brownfield\.md` exists/.test(body), + `commands/${cmd} must guard brownfield exploration on brownfield.md existence` + ); + } +}); + +test('product.md lets the user opt out of brownfield exploration', () => { + // Even when source code is detected, the user may want to start from + // scratch (e.g. reinitializing a project). product.md must ask before + // launching the Explore agent. + const body = readUtf8(path.join(commandsDir, 'product.md')); + assert.ok( + /start from scratch/i.test(body), + 'commands/product.md must offer a "start from scratch" option to skip brownfield exploration' + ); +}); + +test('product.md creates brownfield.md even when all findings are rejected', () => { + // product.md must always create brownfield.md when a brownfield project is + // detected, even if the user rejects every finding. The file acts as a + // sentinel — downstream commands key on its existence to run their own + // explorations. + const body = readUtf8(path.join(commandsDir, 'product.md')); + assert.ok( + /still create the file/i.test(body), + 'commands/product.md must create brownfield.md even when all findings are rejected (sentinel behavior)' + ); +}); + test('context/ references in prompts are internally consistent', () => { // Build a writer/reader map by scanning all prompts. A path is considered // consistent if every reference to it appears in at least one prompt — i.e.