ProjectCLI to expose your installed packs through a company-owned executable. It uses the same planning API available to custom interfaces.
Register the entrypoint
cli.py
main as a console script in your company package:
pyproject.toml
packs order is the execution order. Their names must be unique. Install the Harnest executable alongside the company CLI, or select it explicitly:
Commands and flags
--apply command builds a fresh plan; the CLI does not persist and replay an earlier preview. --json prints a plan without file contents or option values. It can be combined with application flags and does not itself make the command read-only.
Initialize from a template
Pass a Harnest template to your team’s CLI:--template accepts the same template project name, short slug, or HTTPS wheel URL as harnest init. For an HTTPS wheel, optionally pin its contents:
--template cannot be combined with an explicit --framework, --mode, --minimal, or --example. --minimal and --example are mutually exclusive. --template-sha256 requires --template. Without a template, the framework still defaults to ADK and mode to managed.
Use --dry-run to review changes without creating the destination. Planning may download the template; download or validation failures stop before pack hooks run.
Typed pack options
Declare a Pydantic options model when creating the pack. String, integer, and number fields become typed flags. Enums become choices; defaults and validation remain in the Pydantic model.
Use explicit JSON literals for booleans and structured inputs. Avoid field names reserved by the CLI, such as
framework, mode, minimal, example, template, template_sha256, json, and apply.
With multiple packs, flags gain the pack name prefix: --acme-team, --platform-region. Underscores in field names become hyphens in flags.
Options are validated before that pack’s callbacks execute and are not stored in harnest-packs.lock. During upgrades, a pack receives context.options = None unless its options were supplied; read persisted company choices from its configuration file.
Add a company command
add_command returns an argparse.ArgumentParser. Add your arguments and return an integer exit code from the handler:
cli.run(arguments, stdout=..., stderr=...) supports embedded callers and tests. It returns an exit code for normal command execution; argparse retains its usual exit behavior for help and invalid arguments.
Include your company’s Studio
The same company CLI can launch Studio with its bundled UI and resource packs:acme_cli/__init__.py
studio/ contains studio-pack.yaml and its declared assets. Include the directory in your wheel as package data; resolve it relative to your installed module so launch does not depend on the current directory. command is an argv sequence, never a shell string. For a Python module entrypoint it can be (sys.executable, "-m", "acme_cli"), provided that module is executable.
Register the executable and an optional Studio dependency in the company package:
pyproject.toml
acme init, including its initialization hooks and the configured init_args. Command previews and job output show the company command. Use non-secret team defaults in init_args; they appear in the UI and process arguments. The standard creation dialog does not generate fields for arbitrary pack options. Use defaults or a custom UI when those choices need to vary.
Registering Studio also exposes add, compile, test, env, serve, run, extensions, and provision through the company CLI. These delegate to its configured harnest_command, preserving argv and exit codes. Register custom handlers before add_studio to retain ownership of those names. Forwarded processes inherit terminal streams; run(stdout=..., stderr=...) captures project-plan output, not delegated subprocess output.
Ordinary acme init and acme upgrade do not import Studio. acme studio reports an installation error if the optional dependency is missing. Studio’s existing deployment gates and explicit JavaScript trust requirements still apply.
acme studio --safe-ui removes external Studio packs while keeping company CLI initialization. The Studio Packs catalog’s template installation remains a separate reviewed resource-installation flow; it does not run CLI pack initialization hooks. Use Create agent for company CLI initialization.
Typed Studio embedding
add_studio(command=...) takes a list or tuple of argv strings, such as
("acme",) or ["python", "-m", "acme_cli"]. A bare string is rejected by type
checkers and by add_studio at runtime.
Studio ships py.typed metadata. Custom launchers can import
harnest_builder.__main__.main, harnest_builder.app.create_app,
harnest_builder.packs.Packs, and
harnest_builder.pack_distribution.package_packs with typed arguments and
results. harnest_builder.mcp_credentials.CredentialStore provides typed storage
bindings, and harnest_builder.types.Completion describes an optional async
completion hook accepted by create_app. Internal route and process modules
are implementation details rather than a supported embedding API.