Project templates in detail¶
Project templates are directories containing httk_project_template.toml.
They can be selected by an explicit directory, by plugin:id, or by a bare
template ID when exactly one installed template has that ID. A bare ID shared
by multiple plugins is ambiguous and must be qualified.
The httk_project_template.toml manifest¶
The manifest is strict: its only top-level table is [template], and unknown
keys are errors.
[template]
id = "starter"
description = "A small starter project"
files = ["README.md", "src"]
[template.instantiate]
file = "instantiate.py"
[template.parameters.name]
type = "string"
description = "Project display name"
[template.parameters.count]
type = "integer"
default = 1
[template]¶
id is required and must match [a-z0-9._-]+; it must not be . or ..,
and must not start with -. description is an optional string.
files is an optional array of relative POSIX members. Each member may be a
regular file or a directory. Members must remain below the template root,
must not be absolute, contain empty components, ., or .., or traverse a
symlink. They must be unique and may not overlap by containment. The manifest
itself, httk_project_template.toml, and the instantiate hook may not be
listed. Directory members are copied recursively; symlinks and special files
inside them are rejected during instantiation.
[template.instantiate]¶
The table is optional and accepts the required file key. A .py file is run
with the current Python interpreter. A non-Python file must be an executable
regular member. The hook is required when the template declares any
parameters.
[template.parameters.<name>]¶
Parameter names must match [A-Za-z_][A-Za-z0-9_]*. Each parameter table
accepts:
type, required and one ofstring,number,integer,boolean,array, orobject;description, an optional string;default, an optional JSON-compatible value matchingtype.
A parameter with no default is mandatory. A parameter with a default is
optional and receives that default when it is not supplied. number accepts
integers and floating-point numbers but not booleans; integer also excludes
booleans. array and object mean JSON arrays and objects.
Parameters are supplied by repeating --parameter NAME=VALUE. VALUE is
parsed as JSON when possible and is otherwise treated as a literal string.
Quote a literal string as JSON, for example:
httk project init demo --template starter \
--parameter name='"Ada"' --parameter count=3 --parameter enabled=true
The quotes around "Ada" are needed because an unquoted Ada is the JSON
fallback string, while a value such as 3 is parsed as an integer. Unknown
parameters, missing mandatory parameters, and values of the wrong type fail
before the project directory is created.
The instantiate hook¶
The hook receives one JSON request on standard input. It runs with the project
directory as its current working directory (cwd) and with the selected
template files already copied. The request envelope is:
{
"format": "httk-project-template-instantiate",
"format_version": 1,
"template": "starter",
"parameters": {"name": "Ada", "count": 1},
"project": {
"name": "demo",
"description": "",
"project_id": "...",
"root": "/absolute/path/to/demo"
}
}
The project object contains the project information supplied by the caller,
plus root, which is the absolute project root. The httk project init
command supplies name, description, and project_id.
The hook inherits the environment except that variables beginning with
HTTK_ are removed. HTTK_CONFIG_HOME and HTTK_DATA_HOME are retained.
The default hook timeout is 3600 seconds. A Python hook is invoked as
sys.executable HOOK.py; another hook is executed directly.
Write one JSON object to standard output. {} is the empty response. The
optional notes member must be an array of strings; those notes are printed
after initialization. Other response members are accepted but ignored by the
core. Nonzero exit status, invalid JSON, invalid notes, or a timeout fails
instantiation.
The template_instantiate_main helper validates the request envelope and
writes the response for a Python hook. A minimal hook is:
from httk.core.project.templates import TemplateInstantiateRequest, template_instantiate_main
def handle(request: TemplateInstantiateRequest) -> dict[str, object]:
with open("created.txt", "w", encoding="utf-8") as output:
output.write(str(request.parameters["name"]))
return {"notes": ["created project file"]}
template_instantiate_main(handle)
Returning None writes {}. Exceptions are reported as hook failure.
Instantiation and rollback¶
httk project init --template performs the following sequence:
Resolve and validate the template, then validate parameters and apply defaults.
Create the project anchor.
Preflight destination collisions and copy the declared files and directories.
Run the optional instantiate hook.
Copying preserves file modes. Existing project members cause a collision error, and the copy preflight prevents a partial copy from that error. Hook changes are not transactional. If the target directory was fresh, any failure removes it. If the target directory already contained entries, the anchor and any copied or hook-created files remain and the command reports that partial state.