mirror of
https://github.com/bmad-code-org/BMAD-METHOD.git
synced 2026-11-01 04:28:26 +08:00
* feat(toolsmith): add the Toolsmith module with Smithy and bmad-eval Smithy (bmad-toolsmith) builds, converts, reviews, packages, validates and migrates skills, agents and modules from a conversation, with five quality lenses that run after each build. bmad-eval runs baseline, variant, quality and trigger evals. The bmod-toolsmith record and help topics replace the BMad Builder module. Also: validators treat a nested SKILL.md as a template and skip example assets, and the docs site gains a Toolsmith section with stub pages. * fix(toolsmith): memory as small files, name learned at First Breath, uv-only script calls Memory agent shape: - The sanctum drops the single curated MEMORY.md, INDEX.md and the 14-day pruning of session logs. Memory is small files by subject under memory/<kind>/, standing subjects by slug and events by date and slug, plus a write-once raw/ layer for material the owner hands over, with status and distilled_to frontmatter and distillations that link back with source:. memory/pending.md holds what to raise at the next waking. - HOW-I-REMEMBER.md replaces memory-guidance.md: a short guide to the layout, printed at every waking. It took a new name so nobody reads it as the old store. - wake.py prints the identity files and a generated map of memory/ and raw/ (folders with counts, newest dated files, undistilled raw, pending), never the memory bodies. An incomplete sanctum is reported by the files it lacks. - init-sanctum.py reads no config and writes no placeholder owner name or language; setup stopped recording core.user_name and core.communication_language, so it had been writing "friend" and "English" into BOND.md. It now finishes a sanctum an earlier run left incomplete instead of skipping it, which had left the agent unable to wake or be born. - First Breath opens by asking what to call the owner; the reply sets the name and the language, written to BOND.md. The bootloader's config step is gone. - Pulse distills, merges and refreshes in place instead of pruning to a token count. New intake capability template for agents handed transcripts, recordings, notes or documents; the shape's memory gradient offers it. - Tests for both scripts in scripts/tests/test_memory_agent_scripts.py: birth, resume after a cut-off birth, leave a finished sanctum alone, the waking map, pulse. Scripts run under uv: - scan_paths.py gains the python-call rule for python, python3 -m and pip invocations in prompt files, with a test, so the lens round replaces them with uv run. Standards and the memory guide say it in words. Lenses, standards, the shape file, the help topic and the design doc are updated to match. * fix(toolsmith): customization has one writer, memory agents tend without a schedule, bare run is a measurement Standards, the plain-skill and agent shapes and the customization lens say that resolve_customization.py reads and the bmad-customize skill writes: a skill never writes _bmad/custom/, merges TOML itself, or carries a fallback reader for when _bmad/ is absent, and tells users to invoke bmad-customize in one line, offering its install when absent. scan_scripts flags custom-io (a literal naming _bmad/custom or a .user.toml) so the lens round removes such scripts. The memory agent's distill, merge, refresh and raise pass moves from PULSE.md into HOW-I-REMEMBER.md; Pulse only runs it on a schedule. wake.py prints when memory was last tended (memory/.tended) and the session notes written since, and the bootloader tends when notes build up, before greeting or as the session winds down. Standing files replace their sections and append only to History, at turning points; session detail lives in the dated session note. First Breath writes unfinished items, the agent's name included, to memory/pending.md; open-questions.md is gone. Discovery no longer runs every request through a bare subagent and drops the skill when the model copes. A skill that holds a format, preference or convention is warranted by that alone; the bare run happens only when the skill claims to teach the model, the target model is fixed and the user has not asked for speed or autonomy, and it runs the trigger phrase, not the specification. Discovery asks where the skill will run; a distributed skill's comparison belongs to bmad-eval's baseline mode at ship. * feat(toolsmith): ask how a skill registers with bmad, rebuild help to teach, changelog Registration: no build had asked whether a skill joins a module, gets its own record or stays outside the registry, so every skill shipped wired to BMad with no bmod.toml. registry.py reports the installed records, prefixes, bmad version, skills-repo state and unregistered skills; discovery guesses by rule and the read-back carries a Registration line; the pre-pass reports bmod_kind, ship writes the missing record files when it does not match, and the architecture lens flags wired-but-unregistered skills. The single-skill shape counts "the user wants bmad to know it", the multi-skill shape gains a joining section, and every approach scaffolds from the registration line. Help: bmod-toolsmith/help grows from six files to twenty-three small named topics so the bmad help agent can teach as well as route: one file per shape, four craft topics, registration, five walkthroughs, and verified outside references. The router gains prerequisites and drops the docs-site fallback. Changelog: Unreleased entry for Toolsmith replacing the BMad Builder module. * fix(toolsmith): eval runner is harness-neutral, runs are contained, failures exit non-zero bmad-eval shipped one Claude Code adapter and defaulted to Claude's skills folder, config variable and stream format. No adapter ships now. The skill declares [workflow.harness] in its customize.toml (command, skill_dir, home_env, auth_env, env_passthrough, sandbox), empty by default; the model running the first eval works the facts out for its own CLI and records them through bmad-customize, and the runners read them back through the project's customization resolver (--harness <json> for a project without BMad). Trigger detection is a canary token the staged skill asks for at the start of the reply, so no transcript format is parsed. From the PR review: fixture paths and case ids stay inside the case folder; the skill under test is copied into each case, never symlinked; run folders never collide; errored, timed-out or command-not-found runs exit 1 and a missing harness exits 3; a trigger query with a failed attempt is unmeasured, never a pass; the benchmark leaves incomplete runs out of its means; the run records the command and whether a sandbox contained it. Shared pieces live in scripts/eval_common.py with tests against a fake harness. Windows CI: count_tokens sorts by posix string and scan_paths reports posix paths. Help: evals.md says which harness runs an eval and how that is recorded. * fix(toolsmith): eval runs in a clean room outside the project; harness is four keys From a Codex run of the harness-neutral runner: a fresh config folder logged the CLI out, a workspace staged under the project still saw the project's instruction files and installed skills as ancestors, the runner kept YAML quotes in the description, and trigger attempts kept too little. Each attempt now runs in a temporary folder outside the project, made a git root, with the fresh HOME beside it, and the workspace is copied back as cwd/; stdin is closed; parse_skill_md removes YAML quoting; every attempt keeps prompt, transcript, stderr, timing and workspace; token counts come from any turn-level usage block. The harness collapses to four keys: command, skill_dir, env (a table; a value is set as given with "~" meaning the fresh HOME, an empty value forwards the host's) and home_files (files or folders under the host home that keep the CLI logged in). home_env, auth_env, env_passthrough and sandbox are gone; a sandbox is the front of the command. The reference is six lines of guidance and two shapes that ran: Codex (auth.json) and Claude Code on a Mac (keychain linked, USER forwarded). Both passed a real trigger eval. Unattended with nothing recorded, the skill stops and shows the table rather than writing customization.