The atp CLI
Installing the SDK also installs a command-line tool that runs the code generator. It is the same generator the SDK uses on itself: the models, namespaces, and clients under atproto_client/ are all produced by it from the JSON lexicons in lexicons/.
You need it for one of two reasons:
You have lexicons of your own that are not baked into the SDK, and you want typed models and a working client for them. See Custom lexicons.
You are working on the SDK itself and need to regenerate after a lexicon update.
Invoking it
Three spellings, all the same program:
atp --help
atproto --help
python -m atproto_cli --help
Commands accept unambiguous prefixes, so these are equivalent:
atp gen --lexicon-dir ./lexicons custom --output-dir ./my_pkg --package my_pkg
atp g --lexicon-dir ./lexicons c --output-dir ./my_pkg --package my_pkg
An ambiguous prefix fails rather than guessing: atp gen a matches both all and async and reports Too many matches: all, async.
--silent / -s on the root command suppresses progress output:
atp -s gen all
Ruff is required
The generator formats everything it writes by shelling out to Ruff, using a config it owns so the output does not pick up the style of whatever project the output directory happens to sit in.
Ruff is deliberately not a dependency of the SDK, and is only needed when generating. If it is missing you get a RuffNotFoundError telling you to install it:
pip install ruff
The generator looks in your interpreter’s script directory first, then on PATH.
atp gen
All generation lives under gen. One option belongs to the group, not to the subcommands:
--lexicon-dir PATHDirectory of
.jsonlexicon files to generate code for. Defaults to the SDK’s ownlexicons/.
Important
--lexicon-dir must come before the subcommand, because it belongs to gen rather than to what follows it:
atp gen --lexicon-dir ./lexicons custom --output-dir ./my_pkg --package my_pkg
# ^^^^^^^^^^^^^^^^^^^^^^^^ here ^^^^^^ not after here
atp gen custom --lexicon-dir ./lexicons ... fails with Error: '--lexicon-dir' is required. Pass it before the subcommand.
atp gen custom
Generate a standalone, importable package from your own lexicons. This is the one you want if you are not working on the SDK itself. It has its own page.
atp gen --lexicon-dir ./lexicons custom --output-dir ./my_pkg --package my_pkg
Option |
Required |
Meaning |
|---|---|---|
|
yes |
Root of the package to generate. Created if it does not exist. |
|
yes |
Import name of the generated package. Must match the last path segment of |
|
no |
Emit models and namespaces only, no |
atp gen all
Regenerate everything with the SDK’s defaults: models, then namespaces, then subscriptions, then the async client. This is the SDK’s own build step.
atp gen all
atp gen models
atp gen models [--output-dir PATH]
--output-dir is the package root, not the models directory: models are written to its models/ subdirectory.
atp gen namespaces
atp gen namespaces [--output-dir PATH] [--sync-filename sync_ns.py] [--async-filename async_ns.py]
--sync-filename and --async-filename override the generated filenames and must end in .py.
atp gen async
atp gen async
Regenerates async_client.py from client.py by rewriting the source of a hardcoded list of methods.
Warning
This one is maintainer-only. It operates on the SDK’s own atproto_client/client/ files and ignores --output-dir and --lexicon-dir entirely. It will not do anything useful to a package you generated, since atp gen custom already emits both the sync and async sides.
Generating without the CLI
Every subcommand is a thin wrapper over a function you can call yourself. The unit of configuration is CodegenConfig, which is frozen and hashable so that two runs with different lexicons can happen in one process:
from pathlib import Path
from atproto_codegen.config import CodegenConfig
from atproto_codegen.models.generator import generate_models
from atproto_codegen.namespaces.generator import generate_namespaces
from atproto_codegen.subscriptions.generator import generate_subscriptions
config = CodegenConfig(
emit_lexicon_dirs=(Path('./lexicons'),),
output_dir=Path('./my_pkg'),
package='my_pkg',
)
generate_models(config)
generate_namespaces(config)
generate_subscriptions(config)
Useful when generation is a step in a build script rather than something you type. See the code generator reference for the full API.