Skip to content

feat: generate PARAMETERS from the tool registry - #1478

Open
FBISiri wants to merge 3 commits into
basicmachines-co:mainfrom
FBISiri:feat/610-parameters-generator
Open

feat: generate PARAMETERS from the tool registry#1478
FBISiri wants to merge 3 commits into
basicmachines-co:mainfrom
FBISiri:feat/610-parameters-generator

Conversation

@FBISiri

@FBISiri FBISiri commented Sep 5, 2026

Copy link
Copy Markdown

@phernandez — this implements Option A from #610: the registry generator fully owns ## PARAMETERS on every section-3 man page, and the parameter-specific facts that used to live only in hand-curated prose now live in the tools' schema descriptions.

Refs #610

What the generator owns

Scope from the issue thread, and how each point is met:

  1. Every schema property, required first then optional, in schema orderrender_parameters walks the tool's input schema properties in declaration order and partitions by required; nothing is filtered.
  2. Deterministic required/default rendering, no prose merging — each line is - **name** (type, required|optional[, default: X]) — description. The description is the schema description with internal whitespace collapsed; the renderer never reflows or reinterprets prose. $ref enum members resolve to their underlying JSON type so a nullable enum reads string | null rather than a bare null.
  3. Full block replacement on regenreplace_parameters swaps the complete ## PARAMETERS block (or inserts one) on just man-regen; scripts/update_man_pages.py is idempotent (second run: "all pages already match the registry").
  4. Drift test covers every generated pagetest_section_3_parameters_is_exactly_the_registry_rendering iterates all bundled section-3 pages and asserts byte-equality with the live registry rendering (tools with no parameters get no section). A schema change without regeneration fails here and points at the page.
  5. Scenario-focused tests — separate tests for required-first/type rendering, block-only replacement, description normalisation, $ref enum resolution, and the drift check; no parameterised formatting matrix.

Migration of curated PARAMETERS (6 pages → schema descriptions)

Parameter-specific facts moved into Field/Args descriptions in src/basic_memory/mcp/tools/*.py; broader explanations stayed in (or moved to) the pages' DESCRIPTION / GOTCHAS sections.

Page Facts migrated into schema descriptions
write-note(3) directory accepts MCP aliases folder/dir/path, CLI flag --folder; note_type is CLI --type and a type: in content frontmatter takes precedence; metadata not available from CLI; project_id wins over project; project resolution order; json output_format returns conflicts as action: "conflict"
search-notes(3) page/page_size aliases (page_number; limit/per_page); metadata filter semantics (integer values match integer YAML fields); temporal aliases (as_of/valid_on, overlaps/valid_during); kind alias and accepted values
build-context(3) url accepts memory:// URI or bare permalink path; project resolution/fallback
edit-note(3) identifier is a CLI positional argument, not a flag; accepted forms
read-note(3) identifier accepted forms (memory:// URL, permalink, title, search text) and CLI positional; pagination aliases and exhaustion semantics; include_frontmatter CLI flag --frontmatter (--include-frontmatter deprecated alias)
recent-activity(3) timeframe aliases (since/time_range/lookback); project resolution: active/default project first, discovery mode only when neither resolves

The remaining 15 pages were spot-checked for curated-looking content; nothing was dropped.

Verification

  • uv run python scripts/update_man_pages.py ×2 — idempotent, no diff on second run
  • uv run ruff check --fix --unsafe-fixes src tests test-int && uv run ruff format . — clean
  • uv run ty check src tests test-int — only the pre-existing diagnostics also present on a clean main
  • BASIC_MEMORY_ENV=test uv run pytest tests/test_man_pages.py --cov=basic_memory.man — 36 passed, basic_memory/man/__init__.py 100% coverage
  • Full SQLite unit suite — 6940 passed; the only failures are pre-existing on a clean tree (test_claude_issue_triage.py, a chatgpt importer date test) and unrelated to this change

Signed-off (DCO). No tool behaviour changes — only descriptions.

The man-page generator now fully owns the `## PARAMETERS` block on every
section-3 tool page: every schema property is rendered, required first and
then optional, in schema order, with required/default info rendered
deterministically and the whole block replaced on regeneration. `$ref`
enum members resolve to their underlying JSON type so nullable enums read
`string | null` rather than a bare `null`.

Parameter-specific facts that previously lived only in the hand-curated
PARAMETERS prose of six pages (write-note, search-notes, build-context,
edit-note, read-note, recent-activity) — MCP aliases, CLI flags,
precedence rules, config fallbacks, accepted forms, output_format
semantics — are migrated into the tools' Field/param descriptions so the
generated block carries them. Broader explanations stay in the curated
DESCRIPTION / GOTCHAS sections.

The live-registry drift test now checks every generated page against its
actual tool schema, so a schema change without `just man-regen` fails CI.

Refs basicmachines-co#610

Signed-off-by: FBISiri <masteragentsiri@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b395d7ce1b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread scripts/update_man_pages.py Outdated
Comment on lines +47 to +48
if schema.get("properties"):
updated = replace_parameters(updated, render_parameters(page.tool, schema))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove stale PARAMETERS when a tool becomes parameterless

When a registered tool loses its final parameter, this condition skips PARAMETERS processing entirely, so the previously generated block remains in the bundled page and continues advertising removed arguments. The drift test repeats the same properties check, so both regeneration and CI report success; remove any existing PARAMETERS section for an empty schema and test that transition.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — the if schema.get("properties") guard meant a tool that dropped its last parameter would keep its old block forever, and the drift test had the same blind spot.

Fixed in 7307f74: added remove_parameters() and pulled the per-page update into a pure regenerate_page() so an empty schema now strips any existing PARAMETERS section. The drift test asserts the section is absent for parameterless tools (no more silent continue), and there's a transition test covering a page that carries a stale block + {} / {"properties": {}} schemas. Regen is a no-op on the current pages (diagnostics still has no block, cloud_info untouched); man module stays at 100% coverage.

When a registered tool loses its last parameter, the generator now strips any
existing PARAMETERS section instead of skipping it, so a page can no longer keep
advertising removed arguments. The drift test asserts the section is absent for
parameterless tools rather than silently continuing. Addresses the Codex review
on PR basicmachines-co#1478. Refs basicmachines-co#610

Signed-off-by: FBISiri <masteragentsiri@gmail.com>
scripts/ is not a package and CI runs pytest with --import-mode=importlib, so `from scripts.update_man_pages import ...` failed collection on every unit-test job (ModuleNotFoundError: No module named 'scripts'). Load the script with importlib.util.spec_from_file_location, matching tests/test_update_versions.py. Refs basicmachines-co#610

Signed-off-by: FBISiri <masteragentsiri@gmail.com>
@phernandez phernandez changed the title feat(man): generate PARAMETERS from the tool registry feat: generate PARAMETERS from the tool registry Sep 5, 2026
@phernandez

Copy link
Copy Markdown
Member

@codex-review

@chatgpt-codex-connector

Copy link
Copy Markdown

Review Result

No findings on the latest reviewed head (63784c8).

The earlier stale-PARAMETERS concern is fully addressed:

No files were modified during this report-only review, so no commit or follow-up pull request was created.

Verification

  • BASIC_MEMORY_ENV=test uv run pytest tests/test_man_pages.py -q — 39 tests passed; src/basic_memory/man/__init__.py retained 100% coverage.
  • uv run ruff check scripts/update_man_pages.py src/basic_memory/man/__init__.py tests/test_man_pages.py src/basic_memory/mcp/tools/build_context.py src/basic_memory/mcp/tools/edit_note.py src/basic_memory/mcp/tools/read_note.py src/basic_memory/mcp/tools/recent_activity.py src/basic_memory/mcp/tools/search.py src/basic_memory/mcp/tools/write_note.py
  • uv run ty check scripts/update_man_pages.py src/basic_memory/man/__init__.py tests/test_man_pages.py
  • uv run python scripts/update_man_pages.py — reported all pages already match the registry.
  • git diff --check 328f898..HEAD
  • git status --short --branch — working tree clean.

View task →

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants