microsoft/generate-from-typespec
> Generate Python SDK code from a TypeSpec specification using the local emitter. Use this skill when the user wants to generate/regenerate a Python client from a TypeSpec spec, provides a GitHub URL or local path to a TypeSpec project, or says things like "generate from this spec", "emit Python from this tsp", "regenerate the SDK", or "compile this TypeSpec for Python".
npx skills add https://github.com/microsoft/typespec --skill generate-from-typespec
Compiles a TypeSpec specification using the local @typespec/http-client-python
emitter and generates Python SDK code. Supports both branded (@azure-tools/typespec-python)
and unbranded (@typespec/http-client-python) generation.
The caller must provide:
.tsp entry point (e.g., client.tsp, main.tsp)(e.g., https://github.com/Azure/azure-rest-api-specs/tree/main/specification/.../Foundry/src/sdk-service-agentserver-contracts/client.tsp)
azure (branded) or unbranded. If not provided, ask the user.should be written (e.g., ~/Desktop/github/azure-sdk-for-python/sdk/agentserver/azure-ai-agentserver-responses).
If not provided, ask the user.
key=value emitter options theuser wants applied on top of the tspconfig options. These override tspconfig
values if there's a conflict (e.g., models-mode=typeddict).
If the input is a GitHub URL:
owner, repo, ref (branch/commit), and path.~/Desktop/github/<repo-name>, ~/<repo-name>, etc.).
cd <local-repo>
git fetch origin <ref>
git checkout <ref> -- <path-to-spec-dir>/
If the input is a local path:
Verify the file/directory exists. If the path points to a directory, look for
client.tsp or main.tsp as the entry point.
tspconfig.yamlLook for tspconfig.yaml in the same directory as the spec entry point, then
walk up parent directories until one is found.
# Starting from the spec file's directory, search for tspconfig.yaml
current_dir="<spec-dir>"
while [ "$current_dir" != "/" ]; do
if [ -f "$current_dir/tspconfig.yaml" ]; then
echo "Found: $current_dir/tspconfig.yaml"
break
fi
current_dir=$(dirname "$current_dir")
done
Parse the tspconfig.yaml and extract the options block for the Python emitter.
The emitter may appear under either name:
| Flavor | Emitter key in tspconfig.yaml |
| --------- | ------------------------------ |
| Branded | @azure-tools/typespec-python |
| Unbranded | @typespec/http-client-python |
Important cross-flavor rule: If the user requests a different flavor than
what's in the tspconfig, carry over ALL options from the tspconfig's Python
emitter block. For example:
@azure-tools/typespec-python but user wantsunbranded → use all those options, but emit under @typespec/http-client-python
@typespec/http-client-python but user wantsbranded → use all those options, but emit under @azure-tools/typespec-python
If no Python emitter options exist in the tspconfig at all, ask the user for:
emitter-output-dir (required — where to write the generated code)package-name (required)namespace (optional — omit to let @clientNamespace decorators resolve naturally)Use this precedence:
azure or unbranded, use that.flavor option set, mention it to the user and confirm.@azure-tools/typespec-python → azure@typespec/http-client-python → unbranded> "Should I generate as branded (azure flavor) or unbranded?"
Look for the tsp CLI in the spec repo's node_modules:
# Check spec repo root for compiler
< spec-repo-root > /node_modules/@typespec/compiler/cmd/tsp.js
If not found, fall back to the global tsp command, or check the typespec
monorepo's compiler:
~/Desktop/github/typespec/packages/compiler/cmd/tsp.js
Build the tsp compile command using:
.tsp file from Step 1--emit: Always the local emitter path:~/Desktop/github/typespec/packages/http-client-python
--option flags: One for each option from the tspconfig, prefixed withthe local emitter name @typespec/http-client-python (regardless of
what the tspconfig called it). Any additional options provided by the user
are appended last and override tspconfig values if there's a conflict.
Template:
< tsp-cli-path > compile < entry-point.tsp > --emit ~/Desktop/github/typespec/packages/http-client-python \
--option "@typespec/http-client-python.<key1>=<value1>" \
--option "@typespec/http-client-python.<key2>=<value2>" \
...
Option mapping rules:
| tspconfig key | CLI --option key | Notes |
| -------------------- | -------------------- | ------------------------------------------------- |
| emitter-output-dir | emitter-output-dir | Resolve {output-dir}, {service-dir} variables |
| package-mode | package-mode | Usually dataplane or mgmt |
| package-name | package-name | |
| namespace | namespace | Omit if not in tspconfig — see note below |
| api-version | api-version | |
| flavor | flavor | Set to azure for branded, omit for unbranded |
| generate-test | generate-test | |
| generate-sample | generate-sample | |
| models-mode | models-mode | e.g., dpg, msrest, typeddict |
| Any other option | Pass through as-is | |
Namespace note: Do NOT pass --namespace unless it is explicitly set in the
tspconfig or by the user. When omitted, the emitter lets TCGC resolve
@clientNamespace decorators correctly. Passing a namespace when @clientNamespace
is used in the spec can cause incorrect directory nesting.
emitter-output-dir: Always use the value provided by the user (Input #3).
Ignore the emitter-output-dir from the tspconfig — it typically contains
unresolvable template variables like {output-dir} and {service-dir}.
cd <spec-directory>
<constructed-compile-command>
Set a timeout of at least 180 seconds — compilation can take a few minutes.
Check the output:
After successful compilation:
find < output-dir > -type d | sort
models-mode=typeddict).offer to revert non-generated files:
cd <sdk-repo>
git diff --name-status <package-dir>/ | grep -v "<expected-generated-path>"
--namespace trapWhen a TypeSpec uses @clientNamespace to map types into a different namespace,
TCGC resolves the namespace. If you also pass --namespace, TCGC tries to
replace the root of the @clientNamespace value with the flag, which can produce
doubled prefixes like azure.azure.ai.projects.... **Only pass --namespace
when the tspconfig explicitly sets it.**
The local emitter is always @typespec/http-client-python on the CLI --emit
and --option flags. The flavor option controls branded behavior:
--option "@typespec/http-client-python.flavor=azure"flavor option entirely| User request | Option to add |
| -------------- | --------------------------------------------------------------- |
| TypedDict only | --option "@typespec/http-client-python.models-mode=typeddict" |
| No tests | --option "@typespec/http-client-python.generate-test=false" |
| No samples | --option "@typespec/http-client-python.generate-sample=false" |
Take microsoft/generate-from-typespec from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.