Skip to content

sdk: ship the instructions to the repo that installs us, not inside the package - #14

Merged
mohameduk merged 2 commits into
mainfrom
sdk-agent-skills
Aug 28, 2026
Merged

mohameduk merged 2 commits into
mainfrom
sdk-agent-skills

Conversation

@mohameduk

Copy link
Copy Markdown
Owner

A developer runs pip install ubag, their coding agent knows nothing about the protocol, and it invents an API.

Shipping an AGENTS.md inside the package does not fix that. Agents read AGENTS.md, CLAUDE.md and .agents/skills from the project root, never out of site-packages or node_modules. The file has to be copied out to where it will be found.

What this adds

ubag init [--agent|--both|--check]
npx ubag-web init [--agent|--both|--check]

Two skill templates, because the two audiences need opposite things:

skill for covers
ubag-publisher serving a site mounting, the two separate keys, no model in the resolve path, misses reported not guessed, control params never reaching the origin
ubag-agent building an agent the three calls, persisting identity so agent_id stays stable, reading ubag:unresolved correctly

That last one is the one that prevents wrong answers downstream. "This resource says nothing about price" and "the price is nothing" are different answers, and a retrieval layer that blurs them starts returning confident wrong ones.

What it refuses to do

This is the part worth reviewing.

  • An existing AGENTS.md is never modified. It is somebody's file, probably long, and appending to it unasked is how a tool gets uninstalled. The line to add is printed instead. Same for CLAUDE.md.
  • Re-running writes nothing when the content already matches.
  • No pointer under .claude/skills. A one-line CLAUDE.md containing @AGENTS.md was confirmed to pull the whole file into context. The import semantics of a file under .claude/skills were not, and a pointer that silently resolves to nothing is worse than no pointer.

Packaging

Carried deliberately and verified against a built wheel rather than assumed: package-data for the wheel, since packages.find takes modules and not .md files, and bin plus src in the npm files list.

Drive-by fix

__version__ said 0.5.0 while pyproject.toml said 0.6.0, through a release. Harmless while nothing read it. Not harmless now that init stamps the version into a file and compares it back to decide whether a repo's copy is stale, because the check would quietly lie. It now reads installed metadata instead of restating a literal, with a test asserting the two agree.

Template drift

Node keeps its own copy of the templates, because the packages publish separately and neither can reach the other once installed. A test asserts the copies are byte-identical whenever the sibling repo is present, so drift is caught here and not by a user.

Tests

Python 102 passed, Node 110 passed. 29 of those are new and mostly about the refusals above.

🤖 Generated with Claude Code

mohameduk and others added 2 commits August 28, 2026 11:35
…he package

A developer runs `pip install ubag`, their coding agent knows nothing about the
protocol, and it invents an API. Shipping an AGENTS.md inside the package does
not fix that: agents read AGENTS.md, CLAUDE.md and .agents/skills from the
project root, never out of site-packages or node_modules. The file has to be
copied out to where it will be found.

So both SDKs now carry skill templates and an init command that writes them into
the consuming repo:

    ubag init [--agent|--both|--check]
    npx ubag-web init [--agent|--both|--check]

Two audiences, because they need opposite things. The publisher skill covers
mounting the middleware, the two separate keys, and the rules that are
load-bearing: no model runs in the resolve path, misses are reported rather than
guessed, control parameters never reach the origin. The agent skill covers the
three calls, persisting the identity so agent_id stays stable, and reading
ubag:unresolved correctly, since "this resource says nothing about price" and
"the price is nothing" are different answers and blurring them is how a
retrieval layer starts returning confident wrong ones.

What it refuses to do is the part worth reviewing. An existing AGENTS.md is
never modified; it is somebody's file, probably long, and appending to it unasked
is how a tool gets uninstalled. The line to add is printed instead. Same for
CLAUDE.md. Re-running writes nothing when the content already matches.

No pointer is written under .claude/skills. A one-line CLAUDE.md containing
@AGENTS.md was confirmed to pull the whole file into context; the import
semantics of a file under .claude/skills were not, and a pointer that silently
resolves to nothing is worse than no pointer.

Packaging carries the templates deliberately: package-data for the wheel, since
packages.find takes modules and not .md files, and "bin" plus "src" in the npm
files list. Verified against a built wheel rather than assumed.

Also fixes __version__, which said 0.5.0 while pyproject said 0.6.0 through a
release. Harmless while nothing read it. Not harmless now that init stamps the
version into a file and compares it back to decide whether a repo's copy is
stale, because the check would quietly lie. It reads installed metadata instead
of restating a literal, with a test asserting the two agree.

Node keeps its own copy of the templates, because the packages publish
separately and neither can reach the other once installed. A test asserts the
copies are byte-identical whenever the sibling repo is present, so drift is
caught here and not by a user.

Python 102 passed, Node 110 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…his too

tomllib is 3.11+, this package supports 3.10, and CI runs the matrix. The test
that asserts __version__ agrees with pyproject imported tomllib and was the only
red square on the board.

Skipping it below 3.11 was the other option and is worse: 3.10 is the runtime
most likely to be somebody's system default, and it is exactly where an
installed package quietly diverging from the source tree would go unnoticed. A
regex over the one line covers the whole matrix and drops a stdlib dependency
the test never needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mohameduk
mohameduk merged commit 871c8c4 into main Aug 28, 2026
6 checks passed
mohameduk added a commit that referenced this pull request Sep 16, 2026
sdk: ship the instructions to the repo that installs us, not inside the package
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