Skip to content

docs: retarget the CLI to its actual domain; fix prog/console-script drift#2

Merged
OriNachum merged 1 commit into
mainfrom
docs/retarget-to-embeddings-domain
Jul 20, 2026
Merged

docs: retarget the CLI to its actual domain; fix prog/console-script drift#2
OriNachum merged 1 commit into
mainfrom
docs/retarget-to-embeddings-domain

Conversation

@OriNachum

Copy link
Copy Markdown
Contributor

Why

This repo was scaffolded from culture-agent-template. The clone renamed the
package but left two things behind: the CLI still described itself as "a
clonable template for AgentCulture mesh agents"
, and prog disagreed with the
declared console script.

pyproject.toml declares the binary embeddings, while prog and every
help string, docstring, and explain catalog entry said embeddings-cli. So
the commands the CLI printed about itself — including the README quickstart and
its own learn / explain output — were not runnable:

$ uv run embeddings-cli whoami
error: Failed to spawn: `embeddings-cli`

An agent orienting itself via learn or explain got a command map where every
entry failed.

What changed

Domain. README.md now describes what embeddings-cli is actually for:
studying embedding spaces as systems — semantic regions and clusters,
neighborhoods and boundaries, recurring directions of meaning, dense/sparse
areas, coverage gaps, and differences between models — treating an embedding
model as a semantic landscape, and serving as the deterministic tool surface for
a Surveyor agent that records an evidence-backed Atlas. learn,
explain/catalog.py, and overview were retargeted to match.

Naming settled. Invocations read embeddings ...; embeddings-cli stays the
dist name, repo name, and culture.yaml nick. prog is now embeddings, so
every usage and error line is copy-pasteable. The explain catalog keys both
("embeddings",) and ("embeddings-cli",) to the root entry, so either spelling
resolves.

Planned verbs are marked as such. The survey surface — survey, regions,
neighbors, directions, gaps, compare, map — is named in README,
learn, explain, and overview under explicit not yet implemented
headings. None of it is implemented in this PR; this is docs and string
retargeting only. The separation is deliberate so an agent reading the CLI never
mistakes a roadmap verb for a callable one.

Regression guard. test_prog_matches_declared_console_script reads the
console script out of pyproject.toml and asserts prog matches — guarding the
pairing rather than a literal, so a future rename that updates both stays green
while one that updates only one side fails loudly.

CLAUDE.md replaces its roadmap placeholder with the real domain, records
the naming convention, and flags three design constraints the survey surface will
force: runtime dependencies (clustering and map --html need numpy at minimum,
which is incompatible with the inherited zero-dependency property), the rubric
shape of directions discover (a noun with an action-verb also needs an
overview sub-verb), and Atlas persistence (nothing writes to disk today).

Verification

$ uv run pytest -n auto          # 23 passed
$ uv run black --check embeddings tests && uv run isort --check-only embeddings tests
$ uv run flake8 embeddings tests && uv run bandit -c pyproject.toml -r embeddings
$ uv run teken cli doctor . --strict   # all bundles PASS
$ markdownlint-cli2 "**/*.md" ...      # 0 errors

The rubric gate now probes the CLI as embeddings (explain_self: explain embeddings), confirming the console script and prog agree.

Version bumped 0.6.0 → 0.7.0.

Notes

workflow.sh delta reports no .claude/skills.local.yaml on this machine (it is
git-ignored; only the .example is committed), so no sibling alignment dump was
available. These changes are repo-local domain documentation and CLI strings —
no .claude/skills/ content was touched — so no sibling broadcast applies.

  • embeddings-cli (Claude)

…drift

The scaffold clone from culture-agent-template renamed the package but left
the CLI describing itself as "a clonable template for AgentCulture mesh
agents" — and left `prog` disagreeing with the declared console script.

pyproject.toml declares the binary `embeddings`, but `prog` and every help,
docstring, and explain-catalog string said `embeddings-cli`. So the commands
the CLI printed about itself — including the README quickstart and its own
`learn` / `explain` output — were not runnable:

    $ uv run embeddings-cli whoami
    error: Failed to spawn: `embeddings-cli`

Retarget the self-documentation to the real domain (studying embedding spaces
as systems: regions, neighborhoods, directions, gaps, density, cross-model
differences; the Surveyor agent and its evidence-backed Atlas), and settle the
naming: invocations read `embeddings`, while `embeddings-cli` stays the dist,
repo, and nick. The explain catalog keys both spellings to the root entry.

The survey surface (survey, regions, neighbors, directions, gaps, compare,
map) is named under explicit "planned / not yet implemented" headings in
README, learn, explain, and overview, so an agent reading the CLI never
mistakes a roadmap verb for a callable one. None of it is implemented.

test_prog_matches_declared_console_script guards the pairing by reading the
console script out of pyproject.toml rather than asserting a literal, so a
future rename that updates only one side fails loudly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019SWoCWX2v7w5g4f5yUcT6X
@OriNachum

Copy link
Copy Markdown
Contributor Author

/agentic_review

@sonarqubecloud

Copy link
Copy Markdown

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Retarget docs to embeddings domain and align CLI prog with console script

📝 Documentation 🐞 Bug fix 🧪 Tests ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Retarget self-documentation from template scaffolding to embeddings-space “Surveyor/Atlas” domain.
• Standardize all invocations to embeddings ... while keeping embeddings-cli as dist/repo name.
• Add a regression test to prevent prog/console-script drift and extend learn --json metadata.
Diagram

graph TD
  U([User]) --> CS[("pyproject.toml\nconsole script: embeddings")] --> CLI["embeddings/cli/__init__.py\nargparse prog=embeddings"] --> CM["CLI commands\n(whoami/learn/explain/overview/doctor)"] --> EX["embeddings/explain/catalog.py\nmarkdown entries"]
  T["tests/test_cli.py\nprog/script drift guard"] --> CS
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Derive `prog` from installed metadata at runtime
  • ➕ Eliminates hard-coded prog and reduces future drift risk.
  • ➕ Works even when pyproject.toml isn’t present (wheel installs).
  • ➖ More complexity: requires importlib.metadata lookup and handling multiple scripts.
  • ➖ May be ambiguous if multiple console scripts are added later.
2. Single source-of-truth constant (e.g., `COMMAND = "embeddings"`)
  • ➕ Keeps the current architecture but centralizes the name for help/docs.
  • ➕ Simple mechanical adoption across docstrings and emitted text.
  • ➖ Still requires humans to update pyproject.toml; constant doesn’t validate packaging.
  • ➖ Doesn’t prevent drift without an additional test (which this PR already adds).
3. Enforce via packaging/CLI snapshot tests only
  • ➕ Validates the end-user experience (actual invocation text) more directly.
  • ➕ Catches more regressions than prog alone (e.g., README quickstart).
  • ➖ More brittle and higher maintenance (golden outputs change frequently).
  • ➖ May be slower and less targeted than the current pairing test.

Recommendation: The PR’s approach (set prog=&quot;embeddings&quot; and add a pairing test against [project.scripts]) is the best trade-off: it fixes the immediate user-facing breakage and adds a low-maintenance guardrail. If drift remains a recurring issue or if source trees without pyproject.toml become common in testing, consider additionally deriving the command name from installed metadata; otherwise the current solution is sufficiently robust and intentionally simple.

Files changed (16) +582 / -122

Enhancement (2) +69 / -19
learn.pyRetarget 'learn' content and add planned command metadata to JSON +51/-15

Retarget 'learn' content and add planned command metadata to JSON

• Rewrites the self-teaching prompt to describe the embeddings-space domain and explicitly separates planned verbs from implemented ones. Extends 'learn --json' output with 'command' and 'planned_commands' fields.

embeddings/cli/_commands/learn.py

overview.pyAdd planned verbs section to overview output +18/-4

Add planned verbs section to overview output

• Updates overview framing away from template scaffolding and adds a separate planned-verbs list so roadmap commands are clearly labeled as not yet implemented.

embeddings/cli/_commands/overview.py

Bug fix (6) +14 / -11
__init__.pyFix argparse 'prog' to match the installed console script +5/-2

Fix argparse 'prog' to match the installed console script

• Changes 'prog' from 'embeddings-cli' to 'embeddings' and updates the top-level description to match the embeddings-space domain, ensuring help/error text is runnable when copy-pasted.

embeddings/cli/init.py

cli.pyUpdate CLI noun group doc/help text to 'embeddings' invocation +3/-3

Update CLI noun group doc/help text to 'embeddings' invocation

• Adjusts module docstring and help text so the CLI surface introspection examples refer to 'embeddings cli ...' rather than the non-existent 'embeddings-cli' command.

embeddings/cli/_commands/cli.py

doctor.pyMake doctor output lines use 'embeddings' command name +2/-2

Make doctor output lines use 'embeddings' command name

• Updates docstring and the human-readable status header to print 'embeddings doctor: ...', matching the actual runnable command.

embeddings/cli/_commands/doctor.py

explain.pyAlign explain command docs/help with 'embeddings' invocation +2/-2

Align explain command docs/help with 'embeddings' invocation

• Updates docstring and argparse help text so the root path hint references 'embeddings' rather than 'embeddings-cli'.

embeddings/cli/_commands/explain.py

whoami.pyUpdate whoami docstring to correct command name +1/-1

Update whoami docstring to correct command name

• Adjusts the module docstring to reference 'embeddings whoami' rather than 'embeddings-cli whoami'.

embeddings/cli/_commands/whoami.py

__init__.pyFix explain error remediation to use runnable 'embeddings' command +1/-1

Fix explain error remediation to use runnable 'embeddings' command

• Updates the remediation hint for missing explain entries so the suggested listing command is executable ('embeddings explain embeddings-cli').

embeddings/explain/init.py

Tests (2) +29 / -3
test_cli.pyAdd prog/console-script pairing test and update expectations to 'embeddings' +28/-2

Add prog/console-script pairing test and update expectations to 'embeddings'

• Updates help-output assertions to match 'usage: embeddings' and adds 'test_prog_matches_declared_console_script', which reads the console script from 'pyproject.toml' and asserts parser 'prog' matches.

tests/test_cli.py

test_cli_introspection.pyUpdate doctor text expectation to 'embeddings' +1/-1

Update doctor text expectation to 'embeddings'

• Adjusts the doctor text-mode assertion to match the corrected status header ('embeddings doctor').

tests/test_cli_introspection.py

Documentation (4) +468 / -87
CHANGELOG.mdDocument domain retargeting, naming fix, and new regression test +20/-0

Document domain retargeting, naming fix, and new regression test

• Adds a 0.7.0 entry describing the embeddings-space domain framing, the 'embeddings' invocation naming convention, and the new 'prog'/console-script drift guard test.

CHANGELOG.md

CLAUDE.mdReplace scaffold placeholder with embeddings Surveyor/Atlas guidance +261/-19

Replace scaffold placeholder with embeddings Surveyor/Atlas guidance

• Rewrites CLAUDE guidance to describe the embeddings-space domain, planned survey verbs (explicitly not implemented), naming conventions ('embeddings' vs 'embeddings-cli'), and key CLI contract constraints.

CLAUDE.md

README.mdRetarget README to embeddings-space systems study and correct invocations +124/-30

Retarget README to embeddings-space systems study and correct invocations

• Replaces template-oriented framing with the intended embeddings-landscape purpose, adds an explicit status section distinguishing shipping vs planned verbs, and updates quickstart commands to use 'embeddings'.

README.md

catalog.pyRetarget explain catalog to embeddings domain and accept both root spellings +63/-38

Retarget explain catalog to embeddings domain and accept both root spellings

• Rewrites root and verb entries from template scaffolding to the embeddings-space purpose and planned survey surface. Updates catalog semantics so '()', '(embeddings,)', and '(embeddings-cli,)' all resolve to the root entry.

embeddings/explain/catalog.py

Other (2) +2 / -2
pyproject.tomlBump project version to 0.7.0 +1/-1

Bump project version to 0.7.0

• Updates the package version from 0.6.0 to 0.7.0 to reflect the documentation and CLI naming corrections.

pyproject.toml

uv.lockLockfile version bump to 0.7.0 +1/-1

Lockfile version bump to 0.7.0

• Updates the editable package entry to reflect version 0.7.0, keeping the lockfile consistent with 'pyproject.toml'.

uv.lock

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Overstrict scripts test 🐞 Bug ⚙ Maintainability
Description
test_prog_matches_declared_console_script asserts there is exactly one [project.scripts] entry
and then picks the first key, so adding any future console-script alias would fail tests even if
prog still matches the intended primary script. This makes the regression guard more brittle than
its stated goal (pairing), creating avoidable maintenance/test failures.
Code

tests/test_cli.py[R28-50]

+def test_prog_matches_declared_console_script() -> None:
+    """``prog`` must match the console script declared in ``pyproject.toml``.
+
+    The scaffold rename left these disagreeing: pyproject declared the binary
+    ``embeddings`` while ``prog`` and every help/doc string said
+    ``embeddings-cli``, so the commands this CLI printed about itself were not
+    runnable. Guard the pairing rather than the literal, so a future rename that
+    updates both stays green and one that updates only one fails here.
+    """
+    import tomllib
+    from pathlib import Path
+
+    pyproject = Path(__file__).resolve().parents[1] / "pyproject.toml"
+    if not pyproject.is_file():  # pragma: no cover - wheel install, no source tree
+        pytest.skip("no pyproject.toml alongside the package")
+
+    scripts = tomllib.loads(pyproject.read_text(encoding="utf-8"))["project"]["scripts"]
+    assert len(scripts) == 1, "expected exactly one console script"
+    declared = next(iter(scripts))
+
+    from embeddings.cli import _build_parser
+
+    assert _build_parser().prog == declared
Evidence
The test hard-requires exactly one console script and chooses the first key, which will cause
failures if additional scripts/aliases are introduced. The project currently has one script, but
nothing about the runtime requires that to remain true.

tests/test_cli.py[28-50]
pyproject.toml[22-24]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`test_prog_matches_declared_console_script` currently enforces `len(scripts) == 1` and uses `next(iter(scripts))` to choose the declared script name. This is stricter than necessary and will fail if an additional script/alias is added (even if the main pairing remains correct).

## Issue Context
The intended invariant is: the parser's `prog` matches the console script name that points at `embeddings.cli:main`.

## Fix Focus Areas
- tests/test_cli.py[28-50]
- pyproject.toml[22-24]

## Suggested fix
Parse `[project.scripts]`, then select the script name(s) whose value equals `"embeddings.cli:main"` (or `"embeddings.cli:main"` via a constant), assert exactly one such match, and compare that key to `_build_parser().prog`. This keeps the guard while allowing additional unrelated scripts.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Planned commands seem runnable 🐞 Bug ⚙ Maintainability
Description
The README shows a runnable-looking bash block for survey/regions/neighbors/... before the
“Status” section clarifies these verbs are not implemented, so readers may copy/paste and
immediately hit failures. This undercuts the PR’s goal of clearly separating planned verbs from
callable ones.
Code

README.md[R29-41]

+The CLI can embed a representative corpus, survey the resulting space, identify
+regions and directions, compare different embedding models, and generate an
+interpretable map of the model's semantic coverage.
+
+```bash
+embeddings survey corpus.jsonl
+embeddings regions
+embeddings neighbors "agentic culture"
+embeddings directions discover
+embeddings gaps
+embeddings compare model-a model-b
+embeddings map --html
+```
Evidence
The README includes an executable-style command block for planned verbs, and only afterwards (in a
later section) states the surface is not yet implemented.

README.md[29-41]
README.md[55-60]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The README presents a normal bash command block for unimplemented verbs before the explicit not-implemented warning in the Status section. Readers often copy the first code block they see, so this can cause immediate confusion.

## Issue Context
You already have a strong `## Status` disclaimer, but it appears after the example block.

## Fix Focus Areas
- README.md[29-60]

## Suggested fix
Move the command block under a heading like "Planned (not yet implemented)" or place a one-line warning immediately above the block (e.g., "Planned verbs (not yet implemented):") and adjust surrounding text to avoid phrasing like "The CLI can ..." for unimplemented behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread tests/test_cli.py
assert "usage: embeddings" in capsys.readouterr().out


def test_prog_matches_declared_console_script() -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Overstrict scripts test 🐞 Bug ⚙ Maintainability

test_prog_matches_declared_console_script asserts there is exactly one [project.scripts] entry
and then picks the first key, so adding any future console-script alias would fail tests even if
prog still matches the intended primary script. This makes the regression guard more brittle than
its stated goal (pairing), creating avoidable maintenance/test failures.
Agent Prompt
## Issue description
`test_prog_matches_declared_console_script` currently enforces `len(scripts) == 1` and uses `next(iter(scripts))` to choose the declared script name. This is stricter than necessary and will fail if an additional script/alias is added (even if the main pairing remains correct).

## Issue Context
The intended invariant is: the parser's `prog` matches the console script name that points at `embeddings.cli:main`.

## Fix Focus Areas
- tests/test_cli.py[28-50]
- pyproject.toml[22-24]

## Suggested fix
Parse `[project.scripts]`, then select the script name(s) whose value equals `"embeddings.cli:main"` (or `"embeddings.cli:main"` via a constant), assert exactly one such match, and compare that key to `_build_parser().prog`. This keeps the guard while allowing additional unrelated scripts.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread README.md

> What kind of world does this embedding model create?

The CLI can embed a representative corpus, survey the resulting space, identify

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. Planned commands seem runnable 🐞 Bug ⚙ Maintainability

The README shows a runnable-looking bash block for survey/regions/neighbors/... before the
“Status” section clarifies these verbs are not implemented, so readers may copy/paste and
immediately hit failures. This undercuts the PR’s goal of clearly separating planned verbs from
callable ones.
Agent Prompt
## Issue description
The README presents a normal bash command block for unimplemented verbs before the explicit not-implemented warning in the Status section. Readers often copy the first code block they see, so this can cause immediate confusion.

## Issue Context
You already have a strong `## Status` disclaimer, but it appears after the example block.

## Fix Focus Areas
- README.md[29-60]

## Suggested fix
Move the command block under a heading like "Planned (not yet implemented)" or place a one-line warning immediately above the block (e.g., "Planned verbs (not yet implemented):") and adjust surrounding text to avoid phrasing like "The CLI can ..." for unimplemented behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@OriNachum
OriNachum merged commit be4f6e8 into main Jul 20, 2026
8 checks passed
@OriNachum
OriNachum deleted the docs/retarget-to-embeddings-domain branch July 20, 2026 06:50
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.

1 participant