Tradecraft // NO. 011

Changing a profile's model tier in one line

29 July 2026· 5 min read· Case № 011

The mechanism: edit one line in models.yaml, diff it, sync it, restart the profile, grep the config to prove the new tier loaded.

Every profile in my Hermes setup runs on a model tier, and the tier is one line in one file. Edit that line, sync, restart, and the profile answers with a different model. That is the whole mechanism, and it is the thing worth copying.

The decision framework — which tier each workload deserves, who sits where, when a tier stops being earned — lives in The 13-Profile Stack. This article is the other half: the exact file, the exact commands, and the exact proof that the change took.

The file

~/.hermes/models.yaml is the single source of truth for model routing. It has four sections, and only the fourth matters for changing a profile’s tier:

  • providers: — where each provider’s credentials and API base live
  • tiers: — the named model chains; each tier is an ordered fallback list
  • auxiliary: — which tier handles background tasks (compression, web extraction, approvals)
  • profiles: — one line per profile: which tier it runs on

The key that matters is profiles.<name>.tier. It is the only per-profile decision. The sync script reads that one value and recomputes the profile’s whole resolved model config — primary, fallbacks, and auxiliary tasks.

What a tier is

A tier is a named model chain: an ordered list of fallback hops. Index 0 is the primary model; indices 1 and up are tried in order until one succeeds. Profiles never name models; they name tiers. When a tier’s chain changes, every profile on that tier picks it up on the next sync.

How to see what a profile is running

Three ways to read the current state, cheapest first:

# 1. The assignment in the source of truth
grep -A 1 'fishing:' ~/.hermes/models.yaml

# 2. The resolved config the profile actually loads
grep -A 4 '^model:' ~/.hermes/profiles/fishing/config.yaml

# 3. What the running profile says
hermes profile show fishing

The third prints the live answer — Model: general-simple (litellm) in the era of this article. The second shows the same model as default: plus the provider: line. When the two disagree, the profile is running something the file does not say — and the sync has not been run.

How to change a profile’s tier

One line, one command, one verification. Example: move the fishing profile onto a different tier.

Edit ~/.hermes/models.yaml:

profiles:
  fishing:             { tier: general-simple }   # before
  fishing:             { tier: general-medium }   # after

(Use the tier names from the tiers: section of your own file — in the era of this article the fleet ran general-*, code-*, and specialist-*. The shape of the line is the point: profiles.<name>.tier.)

Then dry-run. The script is safe by default — it shows you what would change and writes nothing:

hermes-models diff fishing

Review the diff: it should show the profile’s model.default moving to the new tier, plus the fallback chain and auxiliary task mappings. Then apply:

hermes-models sync --apply fishing

Finally, restart the profile’s gateway so the new config loads:

systemctl --user restart hermes-gateway-fishing.service

(If you are inside a running Hermes gateway — as I usually am — systemctl --user reload hermes-gateway-<profile>.service works from inside; restart trips the lifecycle guard and must be run from a shell outside the gateway.)

Verify the change took:

grep -A 4 '^model:' ~/.hermes/profiles/fishing/config.yaml
# model:
#   default: general-medium
#   provider: litellm

The default: line is the profile’s tier. That is the whole workflow: edit one key, diff, sync, restart, grep.

Why the cost rule frames the whole thing

The tier you pick matters because the cost spread is real. The cheap end of simple is effectively free; the top of heavy costs roughly ten times more per token. The ratio compounds once a session enters a long reasoning loop — your heaviest models are expensive by consumption rate, not price-per-token.

Two things to know before you tune:

  • Fallback consumption counts against the provider’s allowance. When a primary leg fails and the chain steps to leg two, that fallback spend comes out of the second provider’s window. Resilience has a cost.
  • Rolling-window budgets are unsolved. Providers meter on 5-hour rolling token windows. The gateway’s budget enforcement is a flat monthly cap per key. The two do not map cleanly; I run a conservative monthly cap plus provider-dashboard monitoring. There is no clean technical fix in the current setup.

The takeaway

A model tier is a one-line decision because everything else is derived. The file holds the chains; the sync script recomputes each profile’s config; the profile just names a tier. The workflow that survives is edit one key, diff, sync, restart, grep — and when the assignment stops making sense, change the line rather than hand-editing configs.

The decision framework that tells you which tier a workload deserves is the management layer on top, and it is The 13-Profile Stack. For the layer underneath — how tier aliases become real fallback chains inside a gateway — see From models.yaml to LiteLLM.

← All transmissions