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".
- License 许可
- MIT
- 最近更新
- 2026-11-14
- Stars
- ★ 5.9k
- Forks
- 422
01 前言 Front Matter
- name
- generate-from-typespec
- description
- 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".
03 SKILL.md 正文
Generate From TypeSpec Skill
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.
Inputs
The caller must provide:
- Spec path — either:
- A local file path to a
.tspentry point (e.g.,client.tsp,main.tsp) - A raw GitHub URL pointing to a TypeSpec project directory or file
(e.g.,
https://github.com/Azure/azure-rest-api-specs/tree/main/specification/.../Foundry/src/sdk-service-agentserver-contracts/client.tsp)
- A local file path to a
- Flavor —
azure(branded) orunbranded. If not provided, ask the user. - Emitter output directory — the full resolved path where generated code
should be written (e.g.,
~/Desktop/github/azure-sdk-for-python/sdk/agentserver/azure-ai-agentserver-responses). If not provided, ask the user. - Additional options (optional) — any extra
key=valueemitter options the user wants applied on top of the tspconfig options. These override tspconfig values if there's a conflict (e.g.,generate-typeddict=false).
Workflow
Step 1: Resolve the spec path
If the input is a GitHub URL:
- Parse the URL to extract
owner,repo,ref(branch/commit), andpath. - Check if the repository is cloned locally (look under common locations like
~/Desktop/github/<repo-name>,~/<repo-name>, etc.). - If found locally, check out the correct ref/commit if needed:
cd <local-repo> git fetch origin <ref> git checkout <ref> -- <path-to-spec-dir>/ - If not found locally, ask the user where the repo is cloned, or offer to clone it.
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.
Step 2: Locate and parse tspconfig.yaml
Look 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
Step 3: Extract Python emitter options from tspconfig.yaml
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:
- tspconfig has options under
@azure-tools/typespec-pythonbut user wants unbranded → use all those options, but emit under@typespec/http-client-python - tspconfig has options under
@typespec/http-client-pythonbut user wants branded → 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@clientNamespacedecorators resolve naturally)
Step 4: Determine the flavor
Use this precedence:
- If the user explicitly stated
azureorunbranded, use that. - If the tspconfig has a
flavoroption set, mention it to the user and confirm. - If the tspconfig only has one Python emitter key, infer:
@azure-tools/typespec-python→azure@typespec/http-client-python→unbranded
- If still ambiguous, ask the user:
"Should I generate as branded (azure flavor) or unbranded?"
Step 5: Find the TypeSpec compiler
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
Step 6: Construct and run the compile command
Build the tsp compile command using:
- Entry point: The resolved
.tspfile from Step 1 --emit: Always the local emitter path:~/Desktop/github/typespec/packages/http-client-python--optionflags: One for each option from the tspconfig, prefixed with the 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}.
Step 7: Run the compilation
cd <spec-directory>
<constructed-compile-command>
Set a timeout of at least 180 seconds — compilation can take a few minutes.
Check the output:
- Warnings only → success
- Errors → report to the user with the full error output
Step 8: Verify and clean up
After successful compilation:
-
Show the generated directory structure:
find < output-dir > -type d | sort -
Verify the output matches expectations (e.g., TypedDict-only if
models-mode=none). -
If the generation overwrote files in an existing package, warn the user and offer to revert non-generated files:
cd <sdk-repo> git diff --name-status <package-dir>/ | grep -v "<expected-generated-path>"
Notes
The --namespace trap
When 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.
Branded vs unbranded emitter names
The local emitter is always @typespec/http-client-python on the CLI --emit
and --option flags. The flavor option controls branded behavior:
- Branded:
--option "@typespec/http-client-python.flavor=azure" - Unbranded: omit the
flavoroption entirely
Common additional options the user may request
| User request | Option to add |
|---|---|
| TypedDict only | --option "@typespec/http-client-python.models-mode=none" |
| No TypedDicts | --option "@typespec/http-client-python.generate-typeddict=false" |
| No tests | --option "@typespec/http-client-python.generate-test=false" |
| No samples | --option "@typespec/http-client-python.generate-sample=false" |
04 同仓库更多 Skills
test-unbranded-emitter
Build and test the @typespec/http-client-python emitter. Use this skill whenever the user wants to test their local changes to the emitter, run the generator test suite, check if their http-client-python changes are passing, or validate a fix. Triggers on phrases like "test the emitter", "run tests", "check if my changes pass", "run test:generator", "run CI", or any mention of testing/validating changes in the emitter package.
diff-upstream
Regenerate the local emitter and diff the generated code against the upstream baseline checked into autorest.python. Use this skill when the user wants to see how their emitter changes affect generated code compared to what's currently in production, says things like "diff upstream", "compare to baseline", "what changed vs production", "show me the diff", "how does this affect generated code", or wants to validate their changes produce the expected output differences.
writing-python-sdk-spector-mock-api-tests
Writes TypeSpec http-client-python generator mock API tests (azure/unbranded/shared) from a Spector case. Use when given a Spector case link or a PR link that modifies Spector cases under http-specs/azure-http-specs.
pnpm-format
Format the codebase with pnpm and recover from common formatting failures.
minimal-repro
Help create a minimal reproduction for a TypeSpec compiler or emitter bug. Use when a user provides TypeSpec source (pasted code or a GitHub URL) and describes an issue. Reproduces locally and reduces to a single-file repro.
http-client-python-bump-and-release
Create a PR to bump TypeSpec/Azure Tools dependencies, update peer dependencies, or release a new version of the http-client-python package.