Deployment Sop
bybren-llc/safe-agentic-workflow
Deployment workflows, pre-deploy validation, and smoke testing patterns.
Migrate a Talos cluster from talhelper (budimanjojo/talhelper, now archived) to TOPF (postfinance/topf).
$ npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install postfinance/topf migrate-talhelper-to-topf --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/postfinance/topf.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/migrate-talhelper-to-topf .claude/skills/migrate-talhelper-to-topf && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "migrate-talhelper-to-topf" agent skill from https://github.com/postfinance/topf/tree/main/skills/migrate-talhelper-to-topf into .claude/skills/migrate-talhelper-to-topf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-talhelper-to-topf", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/postfinance/topf/tree/main/skills/migrate-talhelper-to-topfType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install postfinance/topf migrate-talhelper-to-topf --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/postfinance/topf.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/migrate-talhelper-to-topf .agents/skills/migrate-talhelper-to-topf && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "migrate-talhelper-to-topf" agent skill from https://github.com/postfinance/topf/tree/main/skills/migrate-talhelper-to-topf into .agents/skills/migrate-talhelper-to-topf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-talhelper-to-topf", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install postfinance/topf migrate-talhelper-to-topf --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/postfinance/topf.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/migrate-talhelper-to-topf .cursor/skills/migrate-talhelper-to-topf && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "migrate-talhelper-to-topf" agent skill from https://github.com/postfinance/topf/tree/main/skills/migrate-talhelper-to-topf into .cursor/skills/migrate-talhelper-to-topf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-talhelper-to-topf", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/postfinance/topf.git --path skills/migrate-talhelper-to-topf--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install postfinance/topf migrate-talhelper-to-topf --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/postfinance/topf.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/migrate-talhelper-to-topf .gemini/skills/migrate-talhelper-to-topf && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "migrate-talhelper-to-topf" agent skill from https://github.com/postfinance/topf/tree/main/skills/migrate-talhelper-to-topf into .gemini/skills/migrate-talhelper-to-topf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-talhelper-to-topf", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install postfinance/topf migrate-talhelper-to-topfInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/postfinance/topf.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/migrate-talhelper-to-topf .github/skills/migrate-talhelper-to-topf && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "migrate-talhelper-to-topf" agent skill from https://github.com/postfinance/topf/tree/main/skills/migrate-talhelper-to-topf into .github/skills/migrate-talhelper-to-topf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-talhelper-to-topf", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install postfinance/topf migrate-talhelper-to-topf --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/postfinance/topf.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/migrate-talhelper-to-topf .opencode/skills/migrate-talhelper-to-topf && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "migrate-talhelper-to-topf" agent skill from https://github.com/postfinance/topf/tree/main/skills/migrate-talhelper-to-topf into .opencode/skills/migrate-talhelper-to-topf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-talhelper-to-topf", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
migrate-talhelper-to-topfMigrate a Talos cluster from talhelper (budimanjojo/talhelper, now archived) to TOPF (postfinance/topf).
Migrate Talhelper To Topf is an agent skill from postfinance/topf. Migrate a Talos cluster from talhelper (budimanjojo/talhelper, now archived) to TOPF (postfinance/topf). Use when the user wants to convert a talconfig.yaml-based setup to topf.yaml + patch files, asks "how do I move off talhelper", or says they want to migrate/switch/transition to topf. Triggers: talhelper, talconfig.yaml, talsecret.sops.yaml, talenv.sops.yaml, "migrate to topf", "switch from talhelper", "talhelper is archived". Covers generating the new topf.yaml, extracting inline node config into patch files…
Its SKILL.md is about 5.7k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `field-mapping.md`).
It sits in Business, Finance & HR, covering Operations and SOPs and Code migrations. It works with Kubernetes and Linux. The repository describes itself as: Talos orchestrator by PostFinance. The licence is MIT.
8 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 232db62. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gityqFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
postfinance.github.iobudimanjojo.github.iogithub.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
REPO_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Migrate Talhelper To Topf loads about 5.7k tokens when it runs. Until then it costs about 209 tokens; SKILL.md has 2,207 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from postfinance/topf at commit 232db62, republished under its MIT licence (© postfinance). 2,207 words, ~5,661 tokens.
.claude/skills/migrate-talhelper-to-topf/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.talhelper is archived (since Aug 2026). TOPF is a recommended successor and the upstream migration guide is canonical: https://postfinance.github.io/topf/main/migration-from-talhelper/
Do the tooling migration on whatever Talos version and config format the cluster runs
today, and prove the TOPF render is equivalent to talhelper's (Step 8) before the first
topf apply. Only then upgrade Talos or move to the v1.14 multi-document format, as a
separate change with the talos-v114-migration skill. Mixing the two makes the first diff
unreviewable: every hunk could be the tool or the format.
TOPF v0.6.0+ renders v1.14 multi-document configs too; that is not a reason to switch
formats during the migration. The examples below use the v1.13 single-document
machine: / cluster: format.
Use this skill when the task involves ANY of:
talconfig.yaml to topf.yaml + patch filestalenv.sops.yaml / talsecret.sops.yaml as part of a topf migrationDo NOT use this skill for:
talos-v114-migration)| Aspect | talhelper | TOPF |
|---|---|---|
| Config file | talconfig.yaml | topf.yaml |
| Patches | Inline in config or separate files | Separate files in all/, <role>/, node/<host>/ |
| Patch format | Strategic merge + JSON patches (RFC 6902) | Strategic merge only (with $patch: delete support) |
| Secrets file | talsecret.sops.yaml | secrets.yaml (same format, just renamed) |
| Env secrets | talenv.sops.yaml + envsubst | SOPS-encrypted data fields in topf.yaml |
| Templating | envsubst / talhelper variables | Go templates (.Data, .Node.Data, sprig functions) |
| Workflow | talhelper genconfig then talosctl apply-config | topf apply (generates + applies in one step) |
field-mapping.md
in this skill directory.Work through the user's talconfig.yaml in this order. Always read the actual
talconfig.yaml (and talenv.sops.yaml / talsecret.sops.yaml if present) in the
repo before editing — do not guess at field names.
Read talconfig.yaml and record:
clusterName, endpoint, talosVersion,
kubernetesVersion, domain, allowSchedulingOnMasters, etc.)patches:, controlPlane: block, worker: block,
inlineManifests:nodes: entry)talenv.sops.yaml / talenv.yaml exists and what keys it holdstalsecret.sops.yaml / talsecret.yaml existstopf.yamlTranslate the top-level cluster fields and the node list. Only these fields have
direct equivalents in topf.yaml; everything else becomes a patch (Step 3).
| talconfig.yaml | topf.yaml | Notes |
|---|---|---|
clusterName | clusterName | unchanged |
endpoint | clusterEndpoint | renamed |
kubernetesVersion | kubernetesVersion | unchanged (keep the same value, e.g. v1.32.8) |
talosVersion | talosVersion | unchanged |
node hostname | node host | renamed |
node ipAddress | node ip | renamed |
node controlPlane: true | node role: control-plane | bool → enum |
node controlPlane: false | node role: worker | bool → enum |
Example minimal topf.yaml:
clusterName: mycluster
clusterEndpoint: https://192.168.1.100:6443
kubernetesVersion: v1.32.8
talosVersion: v1.12.0
nodes:
- host: node-01
ip: 192.168.1.1
role: control-plane
- host: node-02
ip: 192.168.1.2
role: workerFor the full field map (including fields with no direct equivalent), see
field-mapping.md.
Patches live in a directory tree next to topf.yaml (default: same dir; override
with patchesDir). TOPF loads, in order, for each node:
<patchesDir>/all/ # applied to every node
<patchesDir>/control-plane/ # applied to control-plane nodes only
<patchesDir>/worker/ # applied to worker nodes only
<patchesDir>/node/<host>/ # applied to one specific nodeFiles are matched by *.yaml, *.yml, or *.tpl (templated). They are applied in
lexicographic order within each folder, so prefix with two-digit numbers to control
ordering (01-…, 02-…). Lists with a merge key (cluster.inlineManifests by name,
machine.files by path) merge across scopes exactly as they did in talhelper — both
tools use Talos's own strategic-merge patcher — so a control-plane/ patch that adds
inline manifests appends to the all/ list instead of replacing it.
Map each talhelper source to a target directory:
| talhelper source | TOPF patch directory |
|---|---|
top-level patches: | all/ |
top-level controlPlane: patches: | control-plane/ |
top-level worker: patches: | worker/ |
top-level inlineManifests: | all/ (see the @./file gotcha below) |
node-level patches: | node/<host>/ |
| node-level config fields (installDisk, networkInterfaces, nodeLabels, …) | node/<host>/ |
node hostname: (talhelper set it for you) | all/05-hostname.yaml.tpl — see gotchas |
Each patch file is a single standalone YAML document — a strategic merge patch
against the Talos v1.13 machine config (machine: / cluster: maps).
Example per-node install + network patches:
# node/node-01/01-install.yaml
machine:
install:
disk: /dev/nvme0n1# node/node-01/02-network.yaml
machine:
network:
interfaces:
- interface: eno1
dhcp: trueFor a control-plane VIP shared by all CP nodes, put it under control-plane/:
# control-plane/01-vip.yaml
machine:
network:
interfaces:
- interface: eno1
vip:
ip: 192.168.1.100talhelper accepts RFC 6902 JSON patches (arrays of {op, path, value}). TOPF
does not — it only accepts strategic merge patches, and will reject a document
that is a YAML array with an error like "document at index N looks like a JSON
patch (array of operations), which is not supported".
Remove a field (e.g. a node label):
# Before (RFC 6902)
- op: remove
path: /machine/nodeLabels/node.kubernetes.io~1exclude-from-external-load-balancers# After (strategic merge, $patch: delete)
machine:
nodeLabels:
node.kubernetes.io/exclude-from-external-load-balancers:
$patch: deleteNote / in keys is written literally — no ~1 escaping.
Add/replace a field: write the strategic merge directly:
# Before
- op: add
path: /machine/kubelet/extraArgs/rotate-server-certificates
value: "true"# After
machine:
kubelet:
extraArgs:
rotate-server-certificates: "true"If a talhelper patch was already strategic merge (a mapping, not an array), it carries over unchanged — just move it into the right file.
talhelper reads talenv.sops.yaml (or talenv.yaml) into env vars and runs
envsubst on talconfig.yaml and patch files. TOPF has no envsubst.
Pattern A — non-secret values: move them under data: in topf.yaml:
# topf.yaml
data:
controlPlaneEndpoint: 192.168.1.100
domain: mycluster.local# control-plane/01-extra-SANs.yaml.tpl
cluster:
apiServer:
certSANs:
- {{ .Data.controlPlaneEndpoint }}The .tpl suffix triggers Go template rendering. Templates use the sprig function
library and missingkey=error (a missing key is a hard error, not a blank).
Pattern B — secret values: put them under data: in topf.yaml and encrypt
the whole topf.yaml with SOPS (or use vals
references like ref+vault://…). SOPS-encrypted values in topf.yaml are
decrypted at load time and redacted from output by default.
# topf.yaml (SOPS-encrypted)
data:
controlPlaneEndpoint: ENC[AES256_GCM,data:...,type:str]Template files reference them the same way: {{ .Data.controlPlaneEndpoint }}.
Encrypt only the data block so the rest of topf.yaml stays diffable and editable
without sops, and move the values without ever writing plaintext to disk:
# .sops.yaml — first matching rule wins, so list this before any catch-all
creation_rules:
- path_regex: topf\.yaml$
encrypted_regex: ^data$
mac_only_encrypted: true
age: <recipient># placeholders in data:, then encrypt in place, then overwrite each value from talenv
sops encrypt -i topf.yaml
sops set topf.yaml '["data"]["repoToken"]' "\"$(sops -d --extract '["REPO_TOKEN"]' talenv.sops.yaml)\""
sops filestatus topf.yaml # {"encrypted":true}A .tpl file is parsed by Go's template engine in full, YAML comments included — a
literal {{ in a comment fails the render with bad character or function not defined.
Values with characters YAML could misread are safer as {{ .Data.x | quote }}.
Per-node data: a node's data: block is reachable in templates as
.Node.Data.<key> (the node the patch is being rendered for). Use this for
per-node values that used to be envsubst'd with node-specific vars.
talhelper template variables like {{ .MachineConfig … }} do not exist in
TOPF. Replace with the TOPF template context:
| talhelper var | TOPF template |
|---|---|
{{ .ClusterName }} | {{ .ClusterName }} |
| (hostname) | {{ .Node.Host }} |
| (node IP) | {{ .Node.IP }} |
(node data foo) | {{ .Node.Data.foo }} |
(global data foo) | {{ .Data.foo }} |
.MachineConfig.… | not available — restructure as a patch |
talsecret.sops.yaml (or talsecret.yaml) → secrets.yaml. The Talos secrets
bundle format is identical between talhelper and TOPF; only the filename changes.
TOPF looks for secrets.yaml next to topf.yaml by default (override with
secretsPath). Keep it SOPS-encrypted.
git mv talsecret.sops.yaml secrets.yamlDelete talenv.sops.yaml / talenv.yaml — there is no equivalent in TOPF. Its
contents either become data: in topf.yaml (if still needed) or are dropped. Also
delete clusterconfig/ and its .gitignore entries (talenv.yaml, talsecret.yaml);
add output/ instead — that is where topf render writes full configs, secrets included.
# Before (talhelper)
talhelper genconfig
talosctl apply-config --insecure -n 192.168.1.1 --file clusterconfig/mycluster-node-01.yaml
# ...repeat per node
# After (TOPF) — single command, all nodes
topf applyFor an existing cluster being migrated (nodes already running Talos), use
--dry-run first to diff the generated config against the running nodes and
confirm nothing unexpected changes:
topf apply --dry-run
topf applytopf apply generates the machine config from patches + secrets and applies it to
each node over the Talos API (not --insecure file apply). It authenticates with a
client certificate minted from secrets.yaml, so the talhelper-era talosconfig keeps
working too (same secrets bundle, same CA); topf talosconfig regenerates it if needed.
TOPF dials every node's ip (or host) on :50000 directly. There is no
talosctl -e <control-plane> -n <worker> style apid proxying, so a NAT'd or LAN-only
node is only reachable when TOPF runs from a network that reaches it. Use
--nodes-filter to apply the reachable nodes from elsewhere.
Both tools emit Talos-machinery YAML, so the two renders can be diffed directly and
every hunk must be explainable. Take the talhelper baseline before deleting
talconfig.yaml / talenv.sops.yaml:
talhelper genconfig # baseline, one last time
topf render -o /tmp/topf-out
diff <(yq -P . clusterconfig/<cluster>-<host>.yaml) <(yq -P . /tmp/topf-out/<host>.yaml)Harmless hunks: multi-document order (TOPF emits documents in patch order — all/,
then role, then node — where talhelper put node and role documents first; Talos keys
documents by kind + name, so order is irrelevant), and any comment or quoting you changed
inside inline manifests. Anything else is a real difference —
typical culprits are a missing hostname patch, a role schematic that changed, or a field
talhelper defaulted (machine.install.wipe, certSANs) that TOPF does not.
topf schematic-ids must print the IDs already in each node's machine.install.image;
only a genuinely new schematic needs --submit-to-factory.topf apply --dry-run (exit code 2 = changes) shows Talos's own diff against the
running config. That diff is textual, so document reordering appears even when the
parsed config is identical — Talos still reports it as applicable without a reboot.
Anything that was changed in talhelper but never applied to the node surfaces here too;
review it, do not let the migration apply it unnoticed.topf apply with the user's explicit approval.installDisk is not a topf.yaml node fieldIt goes in a patch: machine.install.disk: /dev/nvme0n1 under node/<host>/.
networkInterfaces is not a topf.yaml node fieldIt goes in a patch under machine.network.interfaces (per-node) or
control-plane/ if shared by CP nodes.
schematic / extensionsIn TOPF, set schematicId in topf.yaml (or per node). Prefer the @schematic.yaml
reference form (see the topf configuration docs) over hand-computing the hash. The
schematic YAML is the same shape as talhelper's schematic: block — move it into
its own file.
talhelper also accepts controlPlane.schematic / worker.schematic, and a node-level
schematic replaces the role one rather than merging. Express that as one
schematic.yaml.tpl (schematicId: "@schematic.yaml.tpl") keyed on .Node.Role, or as
per-node schematicId entries, and check the IDs with topf schematic-ids:
customization:
systemExtensions:
officialExtensions:
- siderolabs/crun
{{- if eq .Node.Role "worker" }}
- siderolabs/intel-ucode
{{- end }}imageFactory (self-hosted factory)Set factory: in topf.yaml (or per node). The URL template customization
talhelper exposes is not available in TOPF; if the user relied on a non-default
template, flag it and ask how to proceed.
allowSchedulingOnMasters / allowSchedulingOnControlPlanesBecomes cluster.allowSchedulingOnControlPlanes: true in an all/ patch.
additionalApiServerCertSans / additionalMachineCertSansBecomes cluster.apiServer.certSANs: […] (and/or machine.certSANs) in an all/
patch. Merge with any existing certSANs.
cniConfig, clusterPodNets, clusterSvcNets, domainBecomes cluster.network.cni, cluster.network.podSubnets,
cluster.network.serviceSubnets, cluster.network.dnsDomain in an all/ patch.
patches: entries starting with @./file.yaml (talhelper file includes)The referenced file is already a standalone patch — copy it into the appropriate
patch directory as-is (rename to *.yaml if needed).
inlineManifests[].contents: "@./file.yaml" and skipEnvsubsttalhelper reads the file into contents; TOPF has no include mechanism (no readFile
template function). Two options:
Wrap the file into a plain patch — no new tooling, and the manifest is visible in
topf apply diffs. Go through a temp file: a single environment string is capped at
128 KiB and an Argo CD or Cilium bundle exceeds that.
SRC=./argocd-install.yaml yq -n \
'{"cluster": {"inlineManifests": [{"name": "argo-install", "contents": load_str(strenv(SRC))}]}}' \
> all/60-argo-install.yamlvals ref+file:// in a plain patch (contents: ref+file://argocd-install.yaml).
Needs the vals binary, resolves the path against the working directory, and TOPF
redacts vals-resolved values, so the manifest shows as *** redacted *** in diffs.
skipEnvsubst: true has no equivalent and needs none: plain .yaml patches are never
templated, so $f, ${TMP} and friends survive untouched. The trap is reversed — a
manifest containing {{ must NOT live in a .tpl patch.
talhelper emitted machine.network.hostname (or a HostnameConfig document on newer
Talos) from each node's hostname:. TOPF's host is a display and selection label only.
Without a patch, the first topf apply renames every node to talos-xxx-xxx and the
render diff shows the hostname document missing:
# all/05-hostname.yaml.tpl
apiVersion: v1alpha1
kind: HostnameConfig
auto: "off"
hostname: {{ .Node.Host }}Use machine.network.hostname: {{ .Node.Host }} instead if the baseline render used
that form — match whatever talhelper produced.
extraManifests: (deprecated in talhelper)Treat like patches: — move the referenced files into the patch tree.
overridePatches: true on a nodeTOPF always appends node patches after role patches; there's no override flag.
If the user relied on override semantics, inspect the role-level patch the node
was overriding and decide whether to edit the role patch or put an explicit
$patch: delete in the node patch.
filenameTmplNo equivalent. TOPF doesn't write per-node files to disk by default; it applies directly. Ignore this field.
talosImageURLIn TOPF the installer image comes from factory + schematicId + talosVersion.
If the user pinned a specific talosImageURL, translate to the matching
factory/schematicId/talosVersion triple, or flag it.
machineSpecOnly used by talhelper for genurl image. TOPF's topf upgrade and image
generation use talosVersion, schematicId, platform, secureboot instead.
Map what you can; flag the rest.
Before telling the user they're done, confirm:
topf.yaml exists with clusterName, clusterEndpoint, kubernetesVersion,
and a nodes: list where every node has host, ip, and role.hostname, ipAddress, controlPlane,
installDisk, networkInterfaces, patches, etc.) remain on node entries.all/, plus control-plane/ and/or worker/ if
there were role-level patches, plus node/<host>/ for any per-node config.$patch: delete.{{ .… }} template refs in .tpl files resolve against the TOPF context
(.Data, .Node.Data, .ClusterName, .Node.Host, .Node.IP, …) — no
envsubst ${VAR} and no talhelper .MachineConfig.… left.secrets.yaml exists (renamed from talsecret.sops.yaml); talenv.sops.yaml
is removed or its values folded into data:; sops filestatus reports both
topf.yaml and secrets.yaml encrypted; clusterconfig/ is gone, output/ ignored.topf schematic-ids reproduces the IDs from the
talhelper render.talhelper genconfig vs topf render differ only in document order and hunks you
can name; the rendered files are deleted afterwards.topf apply --dry-run runs clean and the diff against the live cluster matches
expectations.© postfinance, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in skills/migrate-talhelper-to-topf of postfinance/topf.
Open the folder on GitHubat commit 232db62
Migrate Talhelper To Topf next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Migrate Talhelper To Topf this skillpostfinance/topf | 175 | — | ~5.7k | Automated safety check: Pass | MIT | |
| Deployment Sopbybren-llc/safe-agentic-workflow | 423 | — | ~966 | Automated safety check: Notes | MIT | |
| K8s Security PoliciesCybereason-Public/owLSM | 280 | 12 repos | ~2k | Automated safety check: Pass | GPL-2.0 | |
| Helm Chart ScaffoldingCybereason-Public/owLSM | 280 | 13 repos | ~381 | Automated safety check: Pass | GPL-2.0 | |
| Cc Sdd New Agentgotalab/cc-sdd | 3.7k | — | ~1.1k | Automated safety check: Pass | MIT | |
| DBS Business Toolkit Entrydontbesilent2025/dbskill | 11k | — | ~2k | Automated safety check: Pass | Custom licence |
bybren-llc/safe-agentic-workflow
Deployment workflows, pre-deploy validation, and smoke testing patterns.
Cybereason-Public/owLSM
Comprehensive guide for implementing NetworkPolicy, PodSecurityPolicy, RBAC, and Pod Security Standards in Kubernetes.
Cybereason-Public/owLSM
Comprehensive guidance for creating, organizing, and managing Helm charts for packaging and deploying Kubernetes applications.
gotalab/cc-sdd
Add or extend coding-agent support in cc-sdd by executing the SOP in docs/cc-sdd/sop-new-agent.md end-to-end.
dontbesilent2025/dbskill
Chinese-language entry skill for the dontbesilent business toolkit: onboards new users, orchestrates tasks across sub-skills, runs numbered prompts and lists hidden ones.
Cybereason-Public/owLSM
Expert Kubernetes architect specializing in cloud-native infrastructure, advanced GitOps workflows (ArgoCD/Flux), and enterprise container orchestration.
postfinance/topf
Migrate a Talos Linux machine configuration from v1.13 (or earlier) v1alpha1 single-document format to the v1.14 multi-document config format introduced in Talos 1.14.
Works with
Categories
Migrate a Talos cluster from talhelper (budimanjojo/talhelper, now archived) to TOPF (postfinance/topf). Migrate Talhelper To Topf is an agent skill from postfinance/topf. Migrate a Talos cluster from talhelper (budimanjojo/talhelper, now archived) to TOPF (postfinance/topf).
Migrate Talhelper To Topf fits situations like: the user wants to convert a talconfig.yaml-based setup to topf.yaml + patch files; asks how do I move off talhelper; says they want to migrate/switch/transition to topf.
Run `npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a claude-code`. Or copy the skill folder (skills/migrate-talhelper-to-topf in postfinance/topf) into .claude/skills/migrate-talhelper-to-topf in your project. Claude Code loads it when a task matches its description.
Run `npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a codex`. Or copy the skill folder (skills/migrate-talhelper-to-topf in postfinance/topf) into .agents/skills/migrate-talhelper-to-topf in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add postfinance/topf --skill migrate-talhelper-to-topf -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/migrate-talhelper-to-topf, .gemini/skills/migrate-talhelper-to-topf, .github/skills/migrate-talhelper-to-topf and .opencode/skills/migrate-talhelper-to-topf in your project.
Going by SKILL.md and its folder, Migrate Talhelper To Topf needs the command-line tools its instructions call (git and yq) and credentials named REPO_TOKEN. Our summary lists: A credential in REPO_TOKEN.
SKILL.md names 3 domains. As links in the text: postfinance.github.io, budimanjojo.github.io and github.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Migrate Talhelper To Topf is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.7k tokens (SKILL.md is roughly 23k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Migrate Talhelper To Topf: Deployment Sop (bybren-llc/safe-agentic-workflow, 423 stars), K8s Security Policies (Cybereason-Public/owLSM, 280 stars), Helm Chart Scaffolding (Cybereason-Public/owLSM, 280 stars) and Cc Sdd New Agent (gotalab/cc-sdd, 3.7k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
postfinance (a GitHub organization) maintains it in postfinance/topf, which has 175 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on October 2, 2026.
Source: postfinance/topf on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.