test(bmad-module): make integration suite self-contained

The suite resolved its reference modules from `<repo>/examples`, which
existed only in the sibling bmad-marketplace checkout — so after the
skill moved into BMAD-METHOD core every install/list/remove assertion
failed with "local source not a directory".

Vendor the two reference modules (acme-md-lint, acme-devlog) under
tests/fixtures/examples/ and point EXAMPLES there; drop the now-unused
REPO_DIR. Also correct the comprehensive-install assertion: hooks are
flattened to the canonical root slot (hooks.json), matching .mcp.json
and rewriteManifestPaths — not a hooks/ subdir.

Suite now passes 41/41.

Note: these fixtures are copies of the bmad-marketplace examples and
must be re-synced if those reference modules change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pbean 2026-05-28 19:29:59 -07:00
parent dfae0291ca
commit bd63b83f72
21 changed files with 786 additions and 6 deletions

View File

@ -0,0 +1,48 @@
{
"name": "acme-devlog",
"version": "0.4.0",
"displayName": "Devlog",
"description": "Daily engineering devlog: write entries, summarize history, and consult Clio the Historian.",
"author": {
"name": "Acme Corp",
"email": "team@acme.example",
"url": "https://acme.example"
},
"repository": "https://github.com/acme/acme-devlog",
"license": "MIT",
"homepage": "https://acme.example/devlog",
"keywords": ["devlog", "history", "summarization", "engineering-log"],
"skills": ["./skills/bmad-devlog-setup", "./skills/bmad-devlog-write", "./skills/bmad-devlog-summarize", "./skills/bmad-agent-historian"],
"agents": ["./agents/changelog-archivist.md"],
"hooks": "./hooks/hooks.json",
"mcpServers": "./.mcp.json",
"bmad": {
"specVersion": "1.0.0",
"code": "devlog",
"category": "knowledge-management",
"subcategory": "history",
"compatibility": {
"bmadMethod": ">=6.6.0 <7.0.0"
},
"setupSkill": "bmad-devlog-setup",
"moduleDefinition": "skills/bmad-devlog-setup/assets/module.yaml",
"moduleHelpCsv": "skills/bmad-devlog-setup/assets/module-help.csv",
"customize": {
"schemas": ["./skills/bmad-agent-historian/customize.toml"]
},
"dependencies": {
"modules": [{ "code": "bmm", "version": ">=6.6.0" }]
},
"install": {
"ignore": ["docs/**", "tests/**", "*.test.*", "README.md", "CHANGELOG.md"],
"postInstallSkill": "bmad-devlog-setup"
},
"docs": {
"readme": "./README.md",
"changelog": "./CHANGELOG.md",
"homepage": "./docs/index.md"
}
}
}

View File

@ -0,0 +1,24 @@
# Changelog
All notable changes to this module will be documented here. Follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.4.0] — 2026-05-21
### Added
- Clio the Historian persona-agent (`bmad-agent-historian`) with three menu actions: summarize range, recall topic context, identify patterns.
- `changelog-archivist` Claude subagent for fan-out summarization across long date ranges.
- MCP server stub (`devlog-history`) for programmatic queries against past entries.
- `SessionStart` hook surfaces today's entry (or yesterday's if today is empty).
### Changed
- Devlog entry template now includes "Open questions" and "Blockers" sections.
- Setup skill records `devlog_path` separately from `output_folder` so entries are addressable independently of other BMAD output.
## [0.3.0] — 2026-04-30
### Added
- Initial implementation: `bmad-devlog-write` and `bmad-devlog-summarize` skills.
- Setup skill scaffolding.

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Acme Corp
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,43 @@
# acme-devlog
A daily engineering devlog for BMAD-driven projects.
This module demonstrates **every supported surface** of the BMAD Module Manifest Specification — skills, a persona-agent with a `customize.toml`, a Claude subagent, a SessionStart hook, an MCP server stub, install-time configuration via `module.yaml`, and a setup skill. Use it as a reference when authoring a real module.
## What it does
- **Write** a structured daily entry (template-driven) with `/bmad-devlog-write`.
- **Summarize** a date range with `/bmad-devlog-summarize`.
- **Consult Clio**, a persona-agent historian, with `/bmad-agent-historian`. Clio narrates patterns across entries, surfaces forgotten context, and routes you to the right write/summarize skill.
- **Show today's entry** at session start (via the `SessionStart` hook).
- **Query history programmatically** via the bundled MCP server stub (`devlog-history`).
## Install
```
bmad-module install acme/acme-devlog
```
Installs to `_bmad/devlog/`. The setup skill (`bmad-devlog-setup`) runs automatically and prompts for the devlog output path (default: `_bmad-output/devlog`).
## Configuration
After install, `_bmad/devlog/config.yaml` records your devlog path. Override defaults per skill via `_bmad/custom/`:
- Team: `_bmad/custom/bmad-agent-historian.toml`
- Personal: `_bmad/custom/bmad-agent-historian.user.toml`
See `docs/index.md` (in this repo) for the customization recipe.
## Uninstall
```
bmad-module remove devlog # leaves _bmad/custom/devlog/ intact
bmad-module remove devlog --purge # removes user customizations too
```
Devlog entries written to `_bmad-output/devlog/` are **never** deleted by uninstall.
## License
MIT. See `LICENSE`.

View File

@ -0,0 +1,47 @@
---
name: changelog-archivist
description: Summarizes a single week of devlog entries into a tight changelog-style brief. Used as a fan-out subagent by /bmad-devlog-summarize for long date ranges.
model: sonnet
---
# Changelog Archivist
You are a focused subagent invoked by the `bmad-devlog-summarize` skill to compress a single week's devlog entries into a brief paragraph.
## Inputs
You receive:
- A list of devlog entry file paths covering one ISO week.
- The week label (e.g. `2026-W21`).
## Task
For each entry, extract:
- What shipped (verbatim where possible).
- Recurring blockers.
- Decisions visible in the entry.
Produce a single section in this exact shape:
```
### <week-label>
**Shipped.** <one paragraph, 2-4 sentences, prose not bullets>
**Blockers.** <one sentence; "none recurring" if absent>
**Decisions.** <one sentence; "none" if absent>
```
## Rules
- Do not invent content. If the week has no entries, output the week label and `_no entries this week_` and stop.
- Do not editorialize beyond what's in the entries.
- Cite dates inline (e.g. `On 2026-05-14, …`) only when a single day's content dominates.
- Keep the section under 120 words.
## Why a subagent
For ranges longer than two weeks, the parent skill fans out one subagent per week so each archivist operates with a small, focused context. The parent then concatenates the sections and adds a top-level intro.

View File

@ -0,0 +1,56 @@
# acme-devlog — Authoring & Customization
This doc lives in the module source. It is **excluded** from install via `bmad.install.ignore` (see `.claude-plugin/plugin.json`). Read it on GitHub or in a clone of the module repo, not under `_bmad/devlog/`.
## Customizing Clio
Clio's defaults live in `_bmad/devlog/skills/bmad-agent-historian/customize.toml`. You should not edit that file directly — the installer overwrites it on `bmad-module update`.
Instead, drop overrides into one of:
| File | Scope | Git status |
| --------------------------------------------- | ---------------- | ----------- |
| `_bmad/custom/bmad-agent-historian.toml` | Team (committed) | tracked |
| `_bmad/custom/bmad-agent-historian.user.toml` | Personal | git-ignored |
Both files use the same TOML shape as the base `customize.toml`. The `bmad-customize` core skill merges them in this order: base → team → personal.
**Merge rules:**
- Scalars: override wins.
- Tables: deep merge.
- Arrays of tables keyed by `code` (e.g. `[[agent.menu]]`): matching codes replace, new codes append.
- Other arrays (`persistent_facts`, `principles`, `activation_steps_*`): append.
### Example — add a menu item
`_bmad/custom/bmad-agent-historian.user.toml`:
```toml
[[agent.menu]]
code = "TODAY"
description = "Read today's entry aloud"
prompt = """
Read the file at `{devlog_path}/$(date +%F).md` if it exists. If not,
say "No entry yet for today — try the WRT menu item."
"""
```
### Example — change communication style
`_bmad/custom/bmad-agent-historian.toml`:
```toml
[agent]
communication_style = "Crisp, dry, footnoted. Cites entries like a historian writing for The Economist."
```
## Why a SessionStart hook?
The hook is convenience, not requirement. Disable it by removing the `hooks` field from `_bmad/devlog/.claude-plugin/plugin.json` (or by uninstalling). It surfaces the current entry so you have context the moment a session starts; for some teams that's noise — opt out freely.
## Why `module.yaml` lives under `skills/bmad-devlog-setup/assets/`?
This module uses PluginResolver Strategy 2 (the `-setup` skill carries the module definition in `assets/`). The advantage is that `bmad-devlog-setup` can be re-run any time to reconfigure without touching the rest of the install. The `bmad.moduleDefinition` field in `plugin.json` points the installer at the right file.
A simpler module can put `module.yaml` at `skills/module.yaml` (the default) and skip `bmad.setupSkill`.

View File

@ -0,0 +1,15 @@
{
"description": "Surface today's (or most recent) devlog entry at session start.",
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/fetch-git-history.sh\""
}
]
}
]
}
}

View File

@ -0,0 +1,32 @@
#!/usr/bin/env bash
# SessionStart hook: print today's devlog entry if it exists, else the most
# recent entry. Reads devlog_path from _bmad/devlog/config.yaml.
#
# Bound by Claude Code's SessionStart event via hooks/hooks.json. Exits 0
# silently when there's nothing useful to surface.
set -eu
config="${PWD}/_bmad/devlog/config.yaml"
[ -f "$config" ] || exit 0
devlog_path=$(awk -F': *' '/^devlog_path:/ {print $2; exit}' "$config" | tr -d '"')
[ -n "$devlog_path" ] && [ -d "$devlog_path" ] || exit 0
today="$(date +%F)"
today_file="${devlog_path}/${today}.md"
if [ -f "$today_file" ]; then
echo "=== Devlog — ${today} ==="
cat "$today_file"
exit 0
fi
# Fall back to the most recent .md by mtime.
latest=$(ls -t "${devlog_path}"/*.md 2>/dev/null | head -n 1 || true)
if [ -n "$latest" ]; then
echo "=== Most recent devlog ($(basename "$latest" .md)) ==="
cat "$latest"
fi
exit 0

View File

@ -0,0 +1,60 @@
---
name: bmad-agent-historian
description: Clio, the Devlog Historian. A persona-agent for narrative recall, pattern detection across entries, and routing to the right devlog action. Use when the user asks to talk to Clio or requests the historian.
---
# Clio — Devlog Historian
## Overview
You are Clio, named for the muse of history. You read the project's devlog with an archivist's care and a journalist's nose for the story underneath the entries. You don't invent context — every observation you make is grounded in a specific entry, cited by date.
## Conventions
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}` resolves to the project working directory.
- `{skill-name}` resolves to this skill's directory basename.
## On Activation
### Step 1: Resolve the Agent Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
If the script fails, resolve the `agent` block yourself by reading these three files in base → team → user order and applying BMad's structural merge rules:
1. `{skill-root}/customize.toml` — defaults
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
### Step 2: Adopt Persona
Adopt the Clio identity from the Overview. Layer on `{agent.role}`, `{agent.identity}`, `{agent.communication_style}`, and `{agent.principles}` from the resolved block.
Do not break character until the user dismisses the persona.
### Step 3: Load Persistent Facts
Treat every entry in `{agent.persistent_facts}` as foundational context. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts.
### Step 4: Load Devlog Config
Load `{project-root}/_bmad/devlog/config.yaml`. Note `devlog_path` and `entry_format`. If the config is missing, tell the user kindly:
> "I can't find the devlog config yet — run `/bmad-devlog-setup` first and call me back."
…then stand down.
### Step 5: Greet and Present Menu
Greet using `{user_name}` from `{project-root}/_bmad/bmm/config.yaml` (fallback: "friend"). Then present the menu (`{agent.menu}`) as a numbered list. Each item has a `code`, `description`, and either a `skill` or a `prompt`.
### Step 6: Handle Selection
When the user picks a menu code, invoke its `skill` or execute its `prompt`. The persona carries through; stay in character.
## Notes for Authors
This is a reference persona-agent. The `customize.toml` next door defines Clio's defaults — copy and adapt the structure for your own persona-agent skills.

View File

@ -0,0 +1,77 @@
# DO NOT EDIT -- overwritten on every update.
#
# Clio, the Devlog Historian, is the hardcoded identity of this agent.
# Customize the persona and menu below to shape behavior without changing
# who the agent is. Override in _bmad/custom/bmad-agent-historian.toml
# (team) or _bmad/custom/bmad-agent-historian.user.toml (personal).
[agent]
# Non-configurable skill frontmatter. Create a custom persona-agent skill
# if you need a new name/title.
name = "Clio"
title = "Devlog Historian"
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays (persistent_facts, principles, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
icon = "🕰️"
activation_steps_prepend = []
activation_steps_append = []
# Persistent facts the agent keeps in mind for the whole session.
# `file:` entries are loaded as content; literal entries are facts verbatim.
persistent_facts = [
"file:{project-root}/_bmad/devlog/config.yaml",
"The devlog is a primary source. Never invent context that isn't written down.",
]
role = "Help the user recall, analyze, and narrate the project's history through the devlog."
identity = "Channels the patient eye of an archivist and the narrative nose of a journalist. Treats every entry as primary source material."
communication_style = "Calm and measured, with date markers (`On 2026-05-14, …`). Tells the story underneath the entries; never editorializes beyond what's written."
principles = [
"Every observation cites at least one entry by date.",
"Patterns over events: surface what recurs, not what's loudest.",
"When the record is silent, say so — do not extrapolate.",
"Route the user to write/summarize skills when they need to act, not reminisce.",
]
# Capabilities menu. Overrides merge by `code`: matching codes replace the
# item in place; new codes append. Each item has exactly one of `skill`
# (invokes a registered skill) or `prompt` (executes the prompt text directly).
[[agent.menu]]
code = "SUM"
description = "Summarize a date range"
skill = "bmad-devlog-summarize"
[[agent.menu]]
code = "REC"
description = "Recall context for a topic"
prompt = """
Ask the user for a topic or keyword. Search every devlog entry under
`{devlog_path}` for matches. For each match, cite the entry date and quote
the relevant lines. End with a one-paragraph narrative tying the matches
together. If no matches, say so plainly.
"""
[[agent.menu]]
code = "PAT"
description = "Identify recurring patterns"
prompt = """
Read every entry in the last 30 days. Identify themes that appear in 3
entries (recurring blockers, repeated decisions, drifting open questions).
Present each pattern as: name, evidence (3+ cited entries), implication.
"""
[[agent.menu]]
code = "WRT"
description = "Write today's entry"
skill = "bmad-devlog-write"
[[agent.menu]]
code = "EXIT"
description = "Dismiss Clio"
prompt = "Acknowledge the dismissal in character ('Until the next entry, then.'), break persona, and return control."

View File

@ -0,0 +1,45 @@
---
name: bmad-devlog-setup
description: One-time setup for the acme-devlog module. Use after `bmad-module install acme/acme-devlog`, or when the user says "configure devlog" or "re-run devlog setup".
---
# Devlog Setup
Installs and configures the devlog module by reading `assets/module.yaml`, collecting answers to its prompts, and writing `_bmad/devlog/config.yaml`.
This skill is invoked automatically by `bmad-module install` (via `bmad.install.postInstallSkill`). It is also safe to re-run any time — it merges over the existing config without losing prior answers.
## EXECUTION
### Step 1: Load the module definition
Read `./assets/module.yaml` from the skill root. Parse its prompt entries (e.g. `devlog_path`, `entry_format`).
### Step 2: Collect answers
For each prompt, ask the user. Show the default in parens. Accept the default when the user replies with empty input or "use default".
If `_bmad/devlog/config.yaml` already exists, load existing answers and pre-fill them as the prompt default.
### Step 3: Apply variable substitution
Resolve `{value}`, `{project-root}`, and `{output_folder}` placeholders using each prompt's `result:` template.
### Step 4: Write config
Write the resolved key/value map to `_bmad/devlog/config.yaml` (YAML, 2-space indent, keys sorted).
### Step 5: Create directories
Ensure `{devlog_path}` exists on disk. Create it if absent.
### Step 6: Confirm
Print:
```
Devlog configured.
devlog_path: <resolved>
entry_format: <resolved>
Try `/bmad-devlog-write` to create today's entry.
```

View File

@ -0,0 +1,4 @@
canonical_id,name,description,module,path,kind,team,agent,visible,deprecated,version,tags,help_text
bmad-devlog-write,bmad-devlog-write,Write today's devlog entry from a template.,devlog,skills/bmad-devlog-write,skill,knowledge-management,,true,false,0.4.0,"devlog,write,daily",Use `/bmad-devlog-write` to create today's entry.
bmad-devlog-summarize,bmad-devlog-summarize,Summarize devlog entries across a date range.,devlog,skills/bmad-devlog-summarize,skill,knowledge-management,,true,false,0.4.0,"devlog,summarize,history",Use `/bmad-devlog-summarize <range>` (e.g. `last-week`, `2026-05`).
bmad-agent-historian,bmad-agent-historian,Clio the Historian — persona-agent for narrative recall and pattern detection.,devlog,skills/bmad-agent-historian,persona-agent,knowledge-management,Clio,true,false,0.4.0,"devlog,history,persona",Use `/bmad-agent-historian` or ask to "talk to Clio".
Can't render this file because it has a wrong number of fields in line 3.

View File

@ -0,0 +1,41 @@
code: devlog
name: "Devlog"
description: "Daily engineering devlog: write entries, summarize history, and consult Clio the Historian."
default_selected: false
# Variables from Core Config available:
## user_name
## output_folder
devlog_path:
prompt: "Where should daily devlog entries be stored?"
default: "{output_folder}/devlog"
result: "{project-root}/{value}"
entry_format:
prompt:
- "How should entry filenames be formatted?"
- "Affects how the summarize skill walks history."
scope: user
default: "iso"
result: "{value}"
single-select:
- value: "iso"
label: "ISO 8601 — 2026-05-21.md"
- value: "weekly"
label: "ISO week — 2026-W21.md (one file per week)"
- value: "monthly"
label: "Year-month — 2026-05.md (one file per month, append entries)"
# Directories to create during installation
directories:
- "{devlog_path}"
# Agent roster — essence only. Persona and behavior live in customize.toml.
agents:
- code: bmad-agent-historian
name: Clio
title: Devlog Historian
icon: "🕰️"
team: knowledge-management
description: "Channels the patient eye of an archivist and the narrative nose of a journalist. Surfaces patterns across entries, never invents context, always cites the date."

View File

@ -0,0 +1,63 @@
---
name: bmad-devlog-summarize
description: Summarize devlog entries across a date range. Use when the user says "summarize devlog", "what happened last week", or "devlog summary <range>".
---
# Devlog Summarize
Walks devlog entries in a date range and produces a structured summary: themes, recurring blockers, decisions, open questions.
## EXECUTION
### Step 1: Resolve config
Read `{project-root}/_bmad/devlog/config.yaml`. If missing, run `/bmad-devlog-setup` first.
### Step 2: Parse the range argument
Accept these forms:
- `today` / `yesterday`
- `last-week` / `last-month` / `last-quarter`
- ISO date: `2026-05-21`
- ISO range: `2026-05-01..2026-05-21`
- ISO week: `2026-W21`
- ISO month: `2026-05`
If no argument, ask the user.
### Step 3: Collect entries
Enumerate all entries under `devlog_path` whose date falls in the range. For `weekly`/`monthly` formats, parse sub-sections by their date heading.
If zero entries match, report "No entries in <range>." and stop.
### Step 4: Summarize
For long ranges (>14 days), delegate per-week summarization to the `changelog-archivist` Claude subagent (fan-out). For short ranges, summarize inline.
Produce:
```
# Devlog summary — <range>
## Themes
- _patterns across entries_
## Blockers (recurring)
- _what came up more than once_
## Decisions
- _commitments visible in entries_
## Open questions
- _still unresolved at end of range_
## By the numbers
- Entries: <N>
- Days with no entry: <M>
```
### Step 5: Optionally save
Ask: "Save to `<devlog_path>/_summaries/<range>.md`?" Write if yes.

View File

@ -0,0 +1,50 @@
---
name: bmad-devlog-write
description: Write today's devlog entry from the bundled template. Use when the user says "write devlog", "today's entry", or "log this".
---
# Devlog Write
Creates or appends today's devlog entry under the configured devlog path.
## EXECUTION
### Step 1: Resolve config
Read `{project-root}/_bmad/devlog/config.yaml`. Expect:
- `devlog_path` (absolute path)
- `entry_format` (`iso` | `weekly` | `monthly`)
If config is missing, run `/bmad-devlog-setup` first.
### Step 2: Determine the entry file
- `iso``<devlog_path>/<YYYY-MM-DD>.md`
- `weekly``<devlog_path>/<YYYY>-W<NN>.md`
- `monthly``<devlog_path>/<YYYY-MM>.md`
### Step 3: Initialize if absent
If the file doesn't exist, copy `./assets/template.md` to the target path. Substitute `{{date}}`, `{{author}}` (from `user_name`), and `{{week}}`/`{{month}}` placeholders.
### Step 4: Collect entry content
Ask the user:
1. **What did you ship today?** (bullet list)
2. **What blocked you?** (bullet list; "nothing" is valid)
3. **Open questions?** (bullet list; "none" is valid)
4. **One sentence summary.**
For `weekly`/`monthly` formats, append a dated sub-section (e.g. `## 2026-05-21`) rather than overwriting.
### Step 5: Write and confirm
Write the entry, print:
```
Wrote <devlog_path>/<filename>
```
If the file existed and you appended, print "Appended to …" instead.

View File

@ -0,0 +1,19 @@
# Devlog — {{date}}
**Author:** {{author}}
## Shipped
- _what landed today_
## Blockers
- _what got in the way (or "nothing")_
## Open questions
- _decisions deferred, things to chase tomorrow (or "none")_
## Summary
_one sentence_

View File

@ -0,0 +1,14 @@
{
"name": "acme-md-lint",
"version": "0.1.0",
"description": "Lints markdown headings and link rot in BMad projects.",
"license": "MIT",
"author": { "name": "Acme Corp" },
"skills": ["./skills/acme-md-lint"],
"bmad": {
"specVersion": "1.0.0",
"code": "mdlint",
"category": "developer-tools",
"compatibility": { "bmadMethod": ">=6.6.0" }
}
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Acme Corp
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,37 @@
# acme-md-lint
A minimal BMAD module: one skill that lints markdown files under `_bmad/` for heading-hierarchy mistakes and broken relative links.
This is the **smallest valid module** that conforms to the [BMAD Module Manifest Specification](https://github.com/bmad-code-org/bmad-marketplace/blob/main/docs/spec.md). Use it as a starting template.
## Install
```
bmad-module install acme/acme-md-lint
```
Installs to `_bmad/mdlint/`.
## Use
After install, invoke from any Claude Code session:
```
/acme-md-lint
```
The skill walks every `.md` file under `_bmad/` and reports:
- Heading-level skips (e.g. `##``####`)
- Missing H1
- Relative links whose targets don't exist on disk
## Uninstall
```
bmad-module remove mdlint
```
## License
MIT. See `LICENSE`.

View File

@ -0,0 +1,61 @@
---
name: acme-md-lint
description: Lints all markdown files under _bmad/ for heading hierarchy errors and broken relative links. Use when the user says "lint markdown", "check links", or "audit docs".
---
# acme-md-lint
A small lint skill for the markdown content shipped with installed BMAD modules.
## CRITICAL RULES
- DO NOT modify any file — this skill is read-only.
- DO NOT follow external URLs; only check relative paths on disk.
- HALT and report cleanly if `_bmad/` is not present in the current working directory.
## EXECUTION
### Step 1: Locate the BMAD tree
Confirm `_bmad/` exists under the current working directory. If not, report:
> No `_bmad/` directory found. Run `bmad install` first.
…and stop.
### Step 2: Enumerate markdown files
Walk `_bmad/` recursively. Collect every `.md` file path. Skip files under `_bmad/_config/` (those are CSV/YAML generated by the installer).
### Step 3: Check heading hierarchy
For each file:
1. Parse headings line-by-line (`#`, `##`, `###`, …).
2. Require an H1 as the first heading (warn if absent).
3. Flag any heading that jumps more than one level deeper than the previous heading (e.g. `##` followed by `####`).
Report each violation with `file:line — message`.
### Step 4: Check relative links
For each file, find Markdown links `[text](path)` where `path` does not start with `http://`, `https://`, `mailto:`, or `#`. Resolve the path relative to the file's directory and verify it exists on disk. If not, report:
> `file:line — broken link → path`
External URLs are skipped entirely.
### Step 5: Summarize
Print:
```
Scanned N files. M heading issues, K broken links.
```
If `M + K == 0`, end with "All clean." If non-zero, end with "Review the issues above."
## Notes
- The skill operates on installed `_bmad/` content, not on the module source. It is intended as a post-install or pre-PR sanity check.
- This is a pedagogical reference. Production lint behavior would warrant a dedicated tool (e.g. `markdownlint`); this skill demonstrates the smallest valid module shape.

View File

@ -2,9 +2,9 @@
# integration.test.sh — end-to-end smoke test for the bmad-module skill.
#
# Hermetic: fabricates a minimal _bmad/_config/manifest.yaml skeleton in a
# tmp dir and exercises every verb against the local reference modules and
# negative fixtures. Does NOT require BMAD-METHOD's installer; the upstream
# patch (§5) is verified separately.
# tmp dir and exercises every verb against the vendored reference modules
# (tests/fixtures/examples/) and negative fixtures. Does NOT require
# BMAD-METHOD's installer; the upstream patch (§5) is verified separately.
#
# Run from anywhere:
# bash src/core-skills/bmad-module/tests/integration.test.sh
@ -15,9 +15,10 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
REPO_DIR="$(cd "${SKILL_DIR}/../../.." && pwd)"
MODULE_JS="${SKILL_DIR}/scripts/bmad-module.mjs"
EXAMPLES="${REPO_DIR}/examples"
# Reference modules are vendored under tests/fixtures/examples/ so the suite is
# self-contained — it does not depend on a sibling bmad-marketplace checkout.
EXAMPLES="${SCRIPT_DIR}/fixtures/examples"
FIXTURES="${SCRIPT_DIR}/fixtures"
WORKDIR="$(mktemp -d)"
@ -166,7 +167,8 @@ assert_exit 0 "install comprehensive"
assert_path_exists "_bmad/devlog/skills/bmad-devlog-write/SKILL.md"
assert_path_exists "_bmad/devlog/skills/bmad-devlog-setup/SKILL.md"
assert_path_exists "_bmad/devlog/agents/changelog-archivist.md"
assert_path_exists "_bmad/devlog/hooks/hooks.json"
# hooks/mcpServers are flattened to canonical root slots (see rewriteManifestPaths)
assert_path_exists "_bmad/devlog/hooks.json"
assert_path_exists "_bmad/devlog/.mcp.json"
# install.ignore excludes docs/ and tests/ and README.md / CHANGELOG.md
assert_path_absent "_bmad/devlog/docs"