# Packaging for the AMI survey client. # # The point of this file is one line of setup instead of three. Before it, the # measured route meant cloning a repository, running an installer and restarting # the agent. On our own numbers that route converted worse than the remote # connector, which cannot measure anything. Now it is a command an MCP client can # launch on its own: # # { "mcpServers": { "ami-survey": { "command": "uvx", "args": ["ami-survey"] } } } # # Nothing to clone, nothing to keep updated, and the adapter that reads the # runtime's session log is present - which is the only way a run is `measured`. [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "ami-survey" # Read from ami_survey/__init__.py rather than restated here. The MCP # handshake reports the same constant, and a package whose metadata and # handshake disagree sends anyone debugging it to the wrong version. dynamic = ["version"] description = "Measures the cost, tokens and duration of a completed agent workflow from the runtime's session log." readme = "README.md" requires-python = ">=3.9" # An SPDX expression, not the licence text. `license = { file = ... }` inlines the # whole of LICENSE into the `License:` metadata header, which renders on PyPI as a # wall of text where a label belongs. `license-files` still ships the full text in # the distribution. # # Note there is deliberately no `License ::` classifier below: PEP 639 forbids # pairing one with an expression, and PyPI rejects the upload if you do. license = "MIT" license-files = ["LICENSE"] authors = [{ name = "Fred Viner" }] keywords = ["mcp", "agent", "benchmark", "telemetry", "claude", "codex"] # Every one of these is checked against `trove_classifiers`; PyPI rejects an # upload carrying a string that is not on its list, and it does so after the # version number has been spent. classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing", "Topic :: System :: Benchmark", "Topic :: Scientific/Engineering :: Artificial Intelligence", ] # Deliberately empty, and worth keeping that way. The client reads a session log # and posts JSON; the standard library does both. A dependency here is a # dependency on every machine this ever runs on. dependencies = [] [project.urls] Homepage = "https://agentbenchmark.dev" Source = "https://github.com/speedofred/ami-survey-client-v1" Documentation = "https://github.com/speedofred/ami-survey-client-v1/blob/main/GETTING-STARTED.md" Issues = "https://github.com/speedofred/ami-survey-client-v1/issues" [project.scripts] # What `uvx ami-survey` runs: the MCP server over stdio, which is how an agent # expects to launch a local server. ami-survey = "ami_survey.mcp_server:main" [tool.hatch.version] path = "ami-survey/ami_survey/__init__.py" [tool.hatch.build.targets.wheel] packages = ["ami-survey/ami_survey"] # The two things the client reads off disk sit *beside* the package in a # checkout - `ami-survey/config`, `ami-survey/skills`, siblings of # `ami-survey/ami_survey`. A wheel has no beside: the package lands in # site-packages next to other people's libraries. Copying them inside at build # time means the repository layout does not have to change, and `config._resource` # looks in both places and takes whichever exists. [tool.hatch.build.targets.wheel.force-include] "ami-survey/config" = "ami_survey/config" "ami-survey/skills" = "ami_survey/skills" [tool.hatch.build.targets.sdist] include = ["ami-survey/ami_survey", "ami-survey/config", "ami-survey/skills", "README.md", "LICENSE", "pyproject.toml"]