From a0017034741721ddd4a5b1a0790817352008420a Mon Sep 17 00:00:00 2001 From: Alexander Shleyko Date: Mon, 15 Jun 2026 14:08:59 +0200 Subject: [PATCH 1/6] feat: brownfield awareness across product, roadmap, and architecture commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detect existing codebases during onboarding and explore them before the interactive interview. Each command owns a focused exploration domain — product (purpose/audience/features), roadmap (existing capabilities), architecture (tech stack) — and triages findings with the user via accept/correct/reject. Accepted findings accumulate in context/product/brownfield.md so downstream commands avoid duplicate questions. /awos:hire removes the file after onboarding completes. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 6 ++- README.md | 2 +- commands/architecture.md | 36 ++++++++++++-- commands/hire.md | 4 ++ commands/product.md | 29 +++++++++-- commands/roadmap.md | 33 +++++++++++-- tests/lint-prompts.test.js | 99 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 198 insertions(+), 11 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 66b19d8..c944dff 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:hire` 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..835668e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ 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) +> **Running on an existing codebase?** AWOS auto-detects brownfield projects. `/awos:product` explores what your project does, `/awos:roadmap` maps what's already built, and `/awos:architecture` discovers your tech stack — each presenting findings for you to accept, correct, or reject before continuing the normal interview. You can also run an AI readiness audit: install the plugin with `/plugin install awos@awos-marketplace`, then run `/awos:ai-readiness-audit`. [Learn more](plugins/awos/README.md) ### Step 2: Foundation Setup diff --git a/commands/architecture.md b/commands/architecture.md index 73cea4f..a342b74 100644 --- a/commands/architecture.md +++ b/commands/architecture.md @@ -49,12 +49,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: + + + ... brownfield.md contents ... + + + 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. Walk through any new findings with `AskUserQuestion` (Accept / Accept with corrections / Reject), same as earlier commands. Append accepted findings to `context/product/brownfield.md` under a `## Technology` heading. For corrected findings, record the corrected version. + + d. Use the confirmed technology findings to pre-fill the architecture template. Frame the section-by-section walkthrough as "here's what you're using — confirm, and tell me what you want to change or add for the roadmap ahead." + +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**. --- diff --git a/commands/hire.md b/commands/hire.md index 6a3915c..ae8afb5 100644 --- a/commands/hire.md +++ b/commands/hire.md @@ -208,4 +208,8 @@ Report: - **Coverage Report:** path to `context/product/hired-agents.md` - **Gaps Remaining:** any technologies without specific skill coverage +## Step 10: 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. + End with the next command: `/awos:tasks`. diff --git a/commands/product.md b/commands/product.md index 101fc7f..8c1a80d 100644 --- a/commands/product.md +++ b/commands/product.md @@ -62,14 +62,37 @@ 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, this is a brownfield project — 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. Walk through the findings one by one — each discovered entity (purpose, audience signal, feature, journey step) gets its own confirmation. For each finding, use `AskUserQuestion` with three options: + - **Accept** — the finding is accurate as stated. + - **Accept with corrections** — the finding is directionally right but needs adjustment. If chosen, ask the user for their correction. + - **Reject** — the finding is wrong or irrelevant; discard it. + + c. Write all accepted and corrected findings to `context/product/brownfield.md` under a `## Product` heading. For corrected findings, record the corrected version, not the original. Downstream commands (`/awos:roadmap`, `/awos:architecture`) will append their own findings to this file. + +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..b346fc7 100644 --- a/commands/roadmap.md +++ b/commands/roadmap.md @@ -51,9 +51,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: + + + ... brownfield.md contents ... + + + 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. Walk through any new findings with `AskUserQuestion` (Accept / Accept with corrections / Reject), same as `/awos:product` does. Append accepted findings to `context/product/brownfield.md` under a `## Capabilities` heading. For corrected findings, record the corrected version. + + 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..e38425d 100644 --- a/tests/lint-prompts.test.js +++ b/tests/lint-prompts.test.js @@ -657,6 +657,105 @@ 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( + /## Product/.test(body), + 'commands/product.md must write brownfield findings under a "## Product" heading' + ); +}); + +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( + /## Capabilities/.test(body), + 'commands/roadmap.md must append brownfield findings under a "## Capabilities" heading' + ); +}); + +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( + /## Technology/.test(body), + 'commands/architecture.md must append brownfield findings under a "## Technology" heading' + ); +}); + +test('hire.md removes brownfield.md after onboarding completes', () => { + // /awos:hire is the last onboarding command. By this point all brownfield + // knowledge has been absorbed into product-definition.md, roadmap.md, and + // architecture.md. The brownfield file must be cleaned up. + const body = readUtf8(path.join(commandsDir, 'hire.md')); + assert.ok( + body.includes('context/product/brownfield.md'), + 'commands/hire.md must reference context/product/brownfield.md for cleanup' + ); + assert.ok( + /delete|remove/i.test( + body.substring(body.indexOf('context/product/brownfield.md')) + ), + 'commands/hire.md must delete context/product/brownfield.md during its final steps' + ); +}); + +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. + 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` + ); + } +}); + +test('brownfield commands use accept/correct/reject triage for findings', () => { + // All three brownfield-aware commands must walk through findings + // with the user using the same three-option triage pattern. This + // ensures consistent UX across the onboarding flow. + for (const cmd of ['product.md', 'roadmap.md', 'architecture.md']) { + const body = readUtf8(path.join(commandsDir, cmd)); + assert.ok( + /Accept with corrections/i.test(body), + `commands/${cmd} must offer "Accept with corrections" as a triage option for brownfield findings` + ); + assert.ok( + /Reject/i.test(body), + `commands/${cmd} must offer "Reject" as a triage option for brownfield findings` + ); + } +}); + 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. From 05f0dee6ff042c9cb797dd87fea461e8f0f3cff8 Mon Sep 17 00:00:00 2001 From: Alexander Shleyko Date: Tue, 16 Jun 2026 13:21:08 +0200 Subject: [PATCH 2/6] fixup! feat: brownfield awareness across product, roadmap, and architecture commands address PR review feedback - Batch triage via AskUserQuestion (up to 4 per call), Accept/Reject + free-text Other - Replace ambiguous placeholder with explicit fill-in slot in Explore prompts - Align architecture.md wording with product.md ("better defaults, not fewer questions") - Restore AI readiness audit callout in README.md, add brownfield note separately - Strengthen tests: Explore agent launch, detection indicators, anchored headings, dedup directive, inverse guard for product.md, conditional delete shape in hire.md Co-Authored-By: Claude Opus 4.6 --- README.md | 4 +- commands/architecture.md | 6 +-- commands/product.md | 5 +-- commands/roadmap.md | 4 +- tests/lint-prompts.test.js | 84 +++++++++++++++++++++++++++----------- 5 files changed, 70 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 835668e..9106cbe 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,9 @@ 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?** AWOS auto-detects brownfield projects. `/awos:product` explores what your project does, `/awos:roadmap` maps what's already built, and `/awos:architecture` discovers your tech stack — each presenting findings for you to accept, correct, or reject before continuing the normal interview. You can also run an AI readiness audit: install the plugin with `/plugin install awos@awos-marketplace`, then run `/awos:ai-readiness-audit`. [Learn more](plugins/awos/README.md) +> **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 a342b74..5d2c670 100644 --- a/commands/architecture.md +++ b/commands/architecture.md @@ -68,16 +68,16 @@ Follow this logic precisely. The following findings were already confirmed by the user — do not repeat them: - ... brownfield.md contents ... + {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. Walk through any new findings with `AskUserQuestion` (Accept / Accept with corrections / Reject), same as earlier commands. Append accepted findings to `context/product/brownfield.md` under a `## Technology` heading. For corrected findings, record the corrected version. + c. Triage new findings with `AskUserQuestion`, same as `/awos:product` does — batch by category, offer Accept / Reject, user can provide free-text via "Other". Discard rejected findings. Append accepted findings to `context/product/brownfield.md` under a `## Technology` heading. - d. Use the confirmed technology findings to pre-fill the architecture template. Frame the section-by-section walkthrough as "here's what you're using — confirm, and tell me what you want to change or add for the roadmap ahead." + 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. diff --git a/commands/product.md b/commands/product.md index 8c1a80d..355f461 100644 --- a/commands/product.md +++ b/commands/product.md @@ -78,10 +78,7 @@ First, check if the file `context/product/product-definition.md` exists. ") ``` - b. Walk through the findings one by one — each discovered entity (purpose, audience signal, feature, journey step) gets its own confirmation. For each finding, use `AskUserQuestion` with three options: - - **Accept** — the finding is accurate as stated. - - **Accept with corrections** — the finding is directionally right but needs adjustment. If chosen, ask the user for their correction. - - **Reject** — the finding is wrong or irrelevant; discard it. + 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. Write all accepted and corrected findings to `context/product/brownfield.md` under a `## Product` heading. For corrected findings, record the corrected version, not the original. Downstream commands (`/awos:roadmap`, `/awos:architecture`) will append their own findings to this file. diff --git a/commands/roadmap.md b/commands/roadmap.md index b346fc7..e7cc1b0 100644 --- a/commands/roadmap.md +++ b/commands/roadmap.md @@ -67,14 +67,14 @@ Follow this logic precisely. The following findings were already confirmed by the user — do not repeat them: - ... brownfield.md contents ... + {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. Walk through any new findings with `AskUserQuestion` (Accept / Accept with corrections / Reject), same as `/awos:product` does. Append accepted findings to `context/product/brownfield.md` under a `## Capabilities` heading. For corrected findings, record the corrected version. + c. Triage new findings with `AskUserQuestion`, same as `/awos:product` does — batch by category, offer Accept / Reject, user can provide free-text via "Other". Discard rejected findings. Append accepted findings to `context/product/brownfield.md` under a `## Capabilities` heading. 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. diff --git a/tests/lint-prompts.test.js b/tests/lint-prompts.test.js index e38425d..fb58fa8 100644 --- a/tests/lint-prompts.test.js +++ b/tests/lint-prompts.test.js @@ -672,8 +672,23 @@ test('product.md creates context/product/brownfield.md on brownfield detection', 'commands/product.md must reference context/product/brownfield.md as the brownfield findings destination' ); assert.ok( - /## Product/.test(body), - 'commands/product.md must write brownfield findings under a "## Product" heading' + /under 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' ); }); @@ -688,8 +703,8 @@ test('roadmap.md reads brownfield.md and appends a Capabilities section', () => 'commands/roadmap.md must reference context/product/brownfield.md to consume and extend brownfield findings' ); assert.ok( - /## Capabilities/.test(body), - 'commands/roadmap.md must append brownfield findings under a "## Capabilities" heading' + /under a `## Capabilities` heading/.test(body), + 'commands/roadmap.md must append brownfield findings under a "## Capabilities" heading (anchored to brownfield.md context)' ); }); @@ -703,54 +718,77 @@ test('architecture.md reads brownfield.md and appends a Technology section', () 'commands/architecture.md must reference context/product/brownfield.md to consume and extend brownfield findings' ); assert.ok( - /## Technology/.test(body), - 'commands/architecture.md must append brownfield findings under a "## Technology" heading' + /under a `## Technology` heading/.test(body), + 'commands/architecture.md must append brownfield findings under a "## Technology" heading (anchored to brownfield.md context)' ); }); -test('hire.md removes brownfield.md after onboarding completes', () => { +test('hire.md conditionally removes brownfield.md after onboarding completes', () => { // /awos:hire is the last onboarding command. By this point all brownfield // knowledge has been absorbed into product-definition.md, roadmap.md, and - // architecture.md. The brownfield file must be cleaned up. + // architecture.md. The brownfield file must be conditionally cleaned up. const body = readUtf8(path.join(commandsDir, 'hire.md')); assert.ok( - body.includes('context/product/brownfield.md'), - 'commands/hire.md must reference context/product/brownfield.md for cleanup' - ); - assert.ok( - /delete|remove/i.test( - body.substring(body.indexOf('context/product/brownfield.md')) - ), - 'commands/hire.md must delete context/product/brownfield.md during its final steps' + /If `context\/product\/brownfield\.md` exists, delete it/i.test(body), + 'commands/hire.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('brownfield commands use accept/correct/reject triage for findings', () => { - // All three brownfield-aware commands must walk through findings - // with the user using the same three-option triage pattern. This - // ensures consistent UX across the onboarding flow. +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 with corrections/i.test(body), - `commands/${cmd} must offer "Accept with corrections" as a triage option for brownfield findings` + /Accept/.test(body), + `commands/${cmd} must offer "Accept" as a triage option for brownfield findings` ); assert.ok( - /Reject/i.test(body), + /Reject/.test(body), `commands/${cmd} must offer "Reject" as a triage option for brownfield findings` ); } From 7405460280aa8dba1a9616139e4925fa0163c9a1 Mon Sep 17 00:00:00 2001 From: Alexander Shleyko Date: Tue, 16 Jun 2026 15:52:31 +0200 Subject: [PATCH 3/6] fixup! feat: brownfield awareness across product, roadmap, and architecture commands Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 2 +- commands/architecture.md | 8 ++++- commands/hire.md | 4 --- commands/product.md | 2 +- commands/roadmap.md | 2 +- tests/lint-prompts.test.js | 71 ++++++++++++++++++++++++++++++++++---- 6 files changed, 74 insertions(+), 15 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index c944dff..f981e52 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,7 +91,7 @@ Each file in `claude/commands/{name}.md` is a tiny wrapper that points at `.awos 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:hire` removes the file after all knowledge is absorbed into the product, roadmap, and architecture documents. +**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/`): diff --git a/commands/architecture.md b/commands/architecture.md index 5d2c670..3f5e5b6 100644 --- a/commands/architecture.md +++ b/commands/architecture.md @@ -75,7 +75,7 @@ Follow this logic precisely. ") ``` - c. Triage new findings with `AskUserQuestion`, same as `/awos:product` does — batch by category, offer Accept / Reject, user can provide free-text via "Other". Discard rejected findings. Append accepted findings to `context/product/brownfield.md` under a `## Technology` heading. + 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. @@ -114,3 +114,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/hire.md b/commands/hire.md index ae8afb5..6a3915c 100644 --- a/commands/hire.md +++ b/commands/hire.md @@ -208,8 +208,4 @@ Report: - **Coverage Report:** path to `context/product/hired-agents.md` - **Gaps Remaining:** any technologies without specific skill coverage -## Step 10: 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. - End with the next command: `/awos:tasks`. diff --git a/commands/product.md b/commands/product.md index 355f461..26bdf95 100644 --- a/commands/product.md +++ b/commands/product.md @@ -80,7 +80,7 @@ First, check if the file `context/product/product-definition.md` exists. 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. Write all accepted and corrected findings to `context/product/brownfield.md` under a `## Product` heading. For corrected findings, record the corrected version, not the original. Downstream commands (`/awos:roadmap`, `/awos:architecture`) will append their own findings to this file. + 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. diff --git a/commands/roadmap.md b/commands/roadmap.md index e7cc1b0..b2db6cb 100644 --- a/commands/roadmap.md +++ b/commands/roadmap.md @@ -74,7 +74,7 @@ Follow this logic precisely. ") ``` - c. Triage new findings with `AskUserQuestion`, same as `/awos:product` does — batch by category, offer Accept / Reject, user can provide free-text via "Other". Discard rejected findings. Append accepted findings to `context/product/brownfield.md` under a `## Capabilities` heading. + 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. diff --git a/tests/lint-prompts.test.js b/tests/lint-prompts.test.js index fb58fa8..19ca14c 100644 --- a/tests/lint-prompts.test.js +++ b/tests/lint-prompts.test.js @@ -672,7 +672,7 @@ test('product.md creates context/product/brownfield.md on brownfield detection', 'commands/product.md must reference context/product/brownfield.md as the brownfield findings destination' ); assert.ok( - /under a `## Product` heading/.test(body), + /with a `## Product` heading/.test(body), 'commands/product.md must write brownfield findings under a "## Product" heading (anchored to brownfield.md context)' ); }); @@ -723,14 +723,15 @@ test('architecture.md reads brownfield.md and appends a Technology section', () ); }); -test('hire.md conditionally removes brownfield.md after onboarding completes', () => { - // /awos:hire is the last onboarding command. 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. - const body = readUtf8(path.join(commandsDir, 'hire.md')); +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/hire.md must conditionally delete context/product/brownfield.md (guard + delete in one sentence)' + 'commands/architecture.md must conditionally delete context/product/brownfield.md (guard + delete in one sentence)' ); }); @@ -794,6 +795,62 @@ test('brownfield commands use accept/reject triage for 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 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. From d2d490c6c1e8e8949de31cd4c6b36760ec2cc1b0 Mon Sep 17 00:00:00 2001 From: Alexander Shleyko Date: Tue, 16 Jun 2026 16:10:06 +0200 Subject: [PATCH 4/6] fixup! feat: brownfield awareness across product, roadmap, and architecture commands Co-Authored-By: Claude Opus 4.6 --- commands/architecture.md | 1 + commands/roadmap.md | 1 + 2 files changed, 2 insertions(+) diff --git a/commands/architecture.md b/commands/architecture.md index 3f5e5b6..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). --- diff --git a/commands/roadmap.md b/commands/roadmap.md index b2db6cb..e31568d 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:** `context/product/brownfield.md` (produced by `/awos:product` on brownfield projects). - **Primary Input/Output:** `context/product/roadmap.md`. This is the file you will create or update. --- From 74edba3c2ad54276a719471c8ecb8485b748d8dd Mon Sep 17 00:00:00 2001 From: Alexander Shleyko Date: Tue, 16 Jun 2026 16:50:03 +0200 Subject: [PATCH 5/6] fixup! feat: brownfield awareness across product, roadmap, and architecture commands Co-Authored-By: Claude Opus 4.6 --- commands/product.md | 1 + commands/roadmap.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/commands/product.md b/commands/product.md index 26bdf95..44ec565 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. --- diff --git a/commands/roadmap.md b/commands/roadmap.md index e31568d..65bd3df 100644 --- a/commands/roadmap.md +++ b/commands/roadmap.md @@ -21,7 +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:** `context/product/brownfield.md` (produced by `/awos:product` on brownfield projects). +- **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. --- From 1d7b4c12cff14f8d4794b7fa9e4d2534947129e1 Mon Sep 17 00:00:00 2001 From: Alexander Shleyko Date: Wed, 17 Jun 2026 15:29:30 +0200 Subject: [PATCH 6/6] fixup! feat: brownfield awareness across product, roadmap, and architecture commands Co-Authored-By: Claude Opus 4.6 --- commands/product.md | 2 +- tests/lint-prompts.test.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/commands/product.md b/commands/product.md index 44ec565..55eb5ae 100644 --- a/commands/product.md +++ b/commands/product.md @@ -63,7 +63,7 @@ First, check if the file `context/product/product-definition.md` exists. ### Step 2B: Creation Mode -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, this is a brownfield project — run a comprehensive exploration before starting the interview: +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: diff --git a/tests/lint-prompts.test.js b/tests/lint-prompts.test.js index 19ca14c..3539859 100644 --- a/tests/lint-prompts.test.js +++ b/tests/lint-prompts.test.js @@ -839,6 +839,17 @@ test('brownfield commands guard 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