Profiles, revisions, resources, and policies
Read the v2 Machine Profile contract and choose an Apply Policy for each Profile Resource.
A Machine Profile is the source-owned declaration of desired configuration. A Profile Revision is an immutable, validated, signed publication of that profile. JSONC authoring layout and comments do not affect the canonical digest.
Profile shape
The v2 authoring contract contains a stable profile ID, display name, Follower Groups, Profile Resources, and a default schedule:
{
"id": "workstation",
"version": 2,
"name": "Developer workstation",
"groups": [
{ "name": "developers", "description": "Developer tools" }
],
"resources": [],
"scheduleDefault": {
"type": "daily",
"at": "00:00",
"timezone": "local"
}
}Canonfig normalizes omitted defaults and unordered collections before hashing. It rejects duplicate IDs, missing dependencies, dependency cycles, undeclared groups, invalid targets, incompatible policies, and incompatible verification.
Resource kinds and defaults
| Kind | Desired outcome | Default Apply Policy |
|---|---|---|
file | Exact regular-file content and mode, or raw symlink target | replace |
directory | A source-owned tree with explicit directories and modes | mirror-owned |
config | Declared keys in TOML, JSON, or YAML | merge |
skill | A canonical skill tree | replace-if-unmodified |
tool | Installed and verified executable capability | ensure |
credential | Usable local credential reference | require-local |
schedule | Native scheduled synchronization | replace |
Every Profile Resource has a unique ID, kind, target, kind-specific specification, verification contract, optional groups, and optional dependencies. Dependencies form a directed acyclic graph.
Filesystem fidelity
File, directory, and skill resources preserve numeric modes. Directory and skill resources can also declare empty directories. A symlink target remains the exact authored string, so a relative target stays relative to the link:
{
"id": "tools",
"kind": "directory",
"target": "~/.local/tools",
"spec": {
"kind": "directory",
"mode": 493, // 0755
"directories": [
{ "path": "cache", "mode": 488 } // 0750
],
"files": [
{ "path": "current", "content": "", "symlinkTo": "../bin/tool" }
]
},
"verify": { "method": "digest", "digest": "<directory-digest>" }
}JSON numbers are decimal. The comments above show their octal permission forms.
Apply Policies
replacerecords rollback material and atomically replaces an owned target where the platform supports that filesystem operation.mirror-ownedadds and updates desired files, then removes only files previously owned by Canonfig and still unmodified.mergeupdates declared keys through a format-aware codec while preserving the Local Overlay.replace-if-unmodifiedwrites only when current content matches the Applied Resource Record or already matches desired content.ensurereaches and verifies a capability without removing unrelated software.require-localverifies a local credential reference and otherwise produces Human Action Required.
Transfer is not apply
Content-addressed transfer decides which blobs must cross the source boundary. The resource's Apply Policy independently decides how those bytes may affect Observed State.
Verification
The v2 contract supports digest, command, executable-present, credential-present, and symlink verification. Allowed methods depend on resource kind. Verification is mandatory after mutation, including after agent apply.
Applied Resource Records
An Applied Resource Record stores the exact resource revision, digest, mode, raw symlink target, and owned tree entries that Canonfig last applied. This record enables safe mirror deletion, mode-aware drift detection, audit, and recovery. It is not a Local Overlay and does not confer source authority on the follower.