Protocol declarations
The declaration models in axm_init.models.protocol_scaffold describe the
components needed to scaffold a protocol. They validate names and references
before any files are generated.
Protocol model
ProtocolScaffoldDecl requires the three graph-name segments, contracts, and
nodes. Its graph_name property joins domain, unit, and action
with dots. This name is independent from an optional ticket type.
Prompts, phases, and the complete ticket block may be omitted. Omitted collections default to empty lists.
| Component | Required fields | Optional fields |
|---|---|---|
ContractDecl |
name |
— |
PromptDecl |
name, text |
— |
NodeDecl |
name |
contract, prompt |
PhaseDecl |
name |
nodes (defaults to an empty list) |
TicketDecl |
ticket_type, input_contract |
— |
A ticket block is optional as a whole. When present, its
input_contract remains required.
Reference validation
Every supplied reference must resolve inside the same declaration:
- a node contract names a declared contract;
- a node prompt names a declared prompt;
- each phase node names a declared node;
- a ticket input contract names a declared contract.
Validation errors include the unresolved reference. Component names must also be unique within each list, and generated model or factory names must not collide.
All name segments must be safe lowercase Python identifiers. Path separators, parent traversal, absolute paths, reserved words, and extra fields are rejected.
Scaffold, preview and application surface
init_scaffold accepts protocol declarations through the same AXMTool
signature used by MCP and the generated CLI. Set profile="protocols" and a
domain when creating a standalone Python package or workspace member; the
tool records [tool.axm-init.protocols] in that package's
pyproject.toml. The structured result includes the derived distribution
name, package root, and creation mode.
Select kind="protocol_unit" for a new unit or kind="protocol" when
targeting an existing unit. In both cases, also provide unit and one or more
action-only payloads in protocols. Set preview=true to inspect the plan
without mutation; leave it false to apply that exact plan. The shared domain
and unit belong to the request and are injected into every payload before
validation as a strict ProtocolScaffoldDecl. The action then completes each
qualified graph name; plan_protocol_scaffold is the sole source of the
relative operations and rendered contents.
The preview result has the same structured shape through direct AXMTool, MCP, and CLI calls:
| Field | Meaning |
|---|---|
profile |
Selected profile (protocols) |
mode |
unit for protocol planning or application; standalone or member for package creation |
root |
Absolute target package root |
preview |
true for a non-mutating plan; false after application |
created, updated, unchanged, conflicts |
Relative paths grouped by planner status |
protocols |
Qualified logical graph names |
Preview never applies planned file contents or merged metadata. Application
creates or updates only paths carried by the plan and writes the merged
[tool.axm-init.protocols] metadata; it does not invoke a standalone-project
template. Reapplying an owned plan leaves unchanged files byte-for-byte, including
skeletons extended by a compatible implementation.
Before reading its filesystem snapshot, application acquires a lock keyed by the fully resolved target root and holds it through preflight, writes, and any rollback. Concurrent applications through aliases of one root therefore cannot silently overwrite compatible declarations, while applications to distinct roots remain concurrent. Application then resolves every destination and rejects paths outside the root, outward-pointing symlinks, conflicts, and incompatible occupied paths. If a file or metadata write fails after application begins, it removes paths created by that operation, restores the original file and metadata bytes, and releases the root lock. This is process-local application-level coordination and rollback, not cross-process or crash-safe atomicity.
Invalid request combinations are also rejected before any write: protocol
options without a profile, an empty protocol list when unit or preview is set, the profile on a
non-Python framework, or protocol declarations without a unit.
Example
from axm_init.models.protocol_scaffold import ProtocolScaffoldDecl
declaration = ProtocolScaffoldDecl(
domain="dev",
unit="work",
action="exec",
contracts=[
{"name": "work_request"},
{"name": "work_result"},
],
prompts=[
{"name": "implement", "text": "Implement the requested change."},
],
nodes=[
{"name": "prepare"},
{
"name": "implement",
"contract": "work_result",
"prompt": "implement",
},
],
phases=[
{"name": "build", "nodes": ["prepare", "implement"]},
],
ticket={
"ticket_type": "engineering.change",
"input_contract": "work_request",
},
)
assert declaration.graph_name == "dev.work.exec"
Current interface notes
Unit and protocol requests require an existing package with a readable
pyproject.toml and an already-declared [tool.axm-init.protocols] profile
whose domain matches the request. The tool rejects missing profiles or
conflicting domains before mutation; profile adoption remains a lower-level
capability, not an implicit effect of these tool requests.
The orchestrator processes actions sequentially against a virtual inventory,
so later actions see earlier planned content.
Validate the materialized package explicitly with:
This static check requires schema version 1, a distribution named
axm-{domain}, a src/protocols_{domain} module root, and wheel packages
configuration that includes that protocol root. For every declared action, it
also requires protocol.py, the package initializers, and the
contracts/, nodes/, prompts/, and phases/ directories generated
by the planner.
The component inventory is checked in both directions: each declared contract, node, prompt, or phase must have its corresponding local file, and every local component file must be declared in metadata. Findings distinguish declared components missing from disk from local components missing from the inventory, and name the component and corrective path.
When the same explicit category is run on a uv workspace root, the check
evaluates its members that declare the protocol profile. A member layout error
fails the workspace result, whose details retain the member name. Workspaces
without a profiled member remain non-applicable. Every finding carries a file
location and a correction; inspected modules are parsed with axm-ast, never
imported.
ScaffoldResult also carries success, path, message, files_created
and optional distribution. The human message currently remains
Protocol scaffold preview even on application; preview is the authoritative
mode flag. A preview can report conflicts without applying them.
Rollback and the per-root lock are process-local; they do not coordinate writers in separate processes or supply a durable recovery journal. See the operational guide.