A platform lead dropped three printouts on the table and asked which one we should just pick. One was a free hosted path. One was a paid seat quote. One was a self-host estimate with a blank still sitting in the “who owns weekends” cell.
I did not look at the prices first. I asked a ruder question. If this path dies on a Friday, who is on the hook—and how many days does it take to leave?
Token price almost never reverses that answer. Exit days do. Data gravity does. On-call ownership does.
This is a keep / buy / self-host switch for AI coding runtimes. It is a conversation tool, not a scoring gospel. If one variable below flips, the recommendation should flip with it.
The fork is not unit price
Free looks like a rounding error. Paid looks like a line item. Self-host looks like “we already have spare capacity somewhere.”
None of those are the decision. The decision is whether you are buying inference, an SLA, or a control plane. Mix those up and you will standardize the wrong path, then spend a quarter unpicking prompts, evals, and onboarding docs.
I use six fields. Three of them can knock a column out. Fail a hard gate and that column is ineligible. You do not average your way back in.
The 6-field switch
Score each field 1 (low pressure) to 5 (high pressure). Write the definition on the page. If two people cannot agree on the definition, you do not have a score. You have a vibe.
1. Data gravity (hard gate)
Can prompts, repository slices, traces, and eval fixtures leave your network?
- 1: public samples, no customer identifiers, no secrets
- 3: internal service code, redacted logs
- 5: production-adjacent source, customer data, regulated traces
Hard gate: if this field is 5, hosted free is out. Paid hosted is out unless legal already signed a data path. Remaining moves: self-host, or do not send the work to a model.
2. Failure owner (hard gate)
Who gets paged when the path is down, slow, or confidently wrong?
- 1: hobby use, no user-facing commitment
- 3: platform will triage during business hours
- 5: an implicit availability promise and no named human
Hard gate: if this field is 5 and you cannot name a person, every column fails. Do not keep, buy, or self-host a path that has a crowd instead of an owner.
Would you still call it “just a free trial” if the only pager is a Slack channel named #ai-stuff?
3. Review load
Does cheaper generation increase review minutes faster than it saves write minutes?
You do not need a perfect telemetry pipeline. You need a working definition: review minutes per merged change, plus rewind minutes when the change is wrong.
- 1: boilerplate the team already reviews in seconds
- 3: mixed; seniors are absorbing the extra diff
- 5: diffs grew, reverts grew, and nobody budgeted the cleanup
This field rarely knocks out a column by itself. It changes the expiry. High review load means a short clock, not a bigger seat count.
4. Workflow coupling
How many internal artifacts now assume this path exists? Count them. Literally.
- Prompt libraries and “how we use the tool” docs
- CI jobs that call the path
- Eval suites pinned to its behavior
- Onboarding checklists
- Permission grants and secret names
Then score it:
- 1: a handful of personal configs
- 3: a team README and one CI experiment
- 5: the path is in the default developer laptop image
High coupling does not mean “pay more.” It means you do not get to pretend this is still a trial.
5. Control surface
Do you need model pinning, network egress rules, an air-gap, or an audit trail you can produce without opening a vendor ticket?
- 1: any decent model, any week, is fine
- 3: you want logs and a stable system prompt
- 5: you need to pin behavior, restrict egress, or keep weights and traces inside a boundary you operate
Hard gate: a 5 here knocks out hosted free. Paid hosted survives only if the contract actually gives you the controls. A marketing page that says “enterprise” is not a control surface.
6. Exit cost, in engineering days
What actually moves when you switch—prompts, evals, CI, docs, permissions, and the muscle memory in onboarding?
- 1: under 3 engineering days
- 3: one to two weeks
- 5: more than 15 engineering days, or nobody can even inventory the artifacts
If exit is a 5, a price of zero is a product decision you already made. You just did not put it on a P&L.
Hard knockouts, before you add scores
Do not average a knockout.
- Data gravity = 5 → hosted free ineligible. Paid hosted ineligible without a signed data path. Remaining options: self-host or refuse.
- Failure owner = 5 with no named human → all options ineligible until you name someone.
- Control surface = 5 → hosted free ineligible.
- Exit cost = 5 and no archive rule → you may pilot. You may not standardize.
Everything else is a weighted conversation.
Worked example (labeled hypothetical)
I am not going to invent a customer. Here is a filled sheet for a composite 12-engineer backend group that a platform team supports. Treat the numbers as a rehearsal, not a benchmark.
| Field | Score | Note |
|---|---|---|
| Data gravity | 2 | Internal services, secret-scanning on, no customer PII in prompts |
| Failure owner | 3 | Platform owns business-hours triage; no weekend page |
| Review load | 3 | Diffs are fatter; revert rate not measured yet |
| Workflow coupling | 2 | One README, no CI hook |
| Control surface | 2 | No air-gap; pinning would be nice, not required |
| Exit cost | 2 | Personal prompt files, nothing in the laptop image |
Read that left to right. Hosted free is still eligible. Paid is optional, not required. Self-host is optional, and probably a distraction, because nobody offered to own weekends.
The line I would write on the page: keep a hosted free path as a time-boxed exception, 45-day expiry, named owner, no CI hook. Re-score before anyone adds it to the developer image.
Now flip one variable. Legal says customer source may appear in prompts next sprint. Data gravity becomes 5. The free hosted column dies on the hard gate. You do not “try it for one more month.” You stop, or you self-host inside the boundary, or you wait for a contract.
That is the point of the switch. One field should be able to reverse you.
A reproducible scoring artifact
Copy this YAML, fill it in a PR, and refuse to discuss vendors until the PR has an owner and an expiry.
# keep-buy-selfhost-switch.yml
# Conversation tool. Not objective truth.
decision:
team: "backend-platform-composite"
owner: "platform-lead-name"
expires_on: "2026-10-21" # 45 days from 2026-09-06
status: "draft"
fields:
data_gravity: { score: 2, hard_gate_at: 5, notes: "no customer PII in prompts" }
failure_owner: { score: 3, hard_gate_at: 5, named_human: "platform-lead-name" }
review_load: { score: 3, hard_gate_at: null, notes: "revert rate not measured" }
workflow_coupling: { score: 2, hard_gate_at: null, artifact_count: 1 }
control_surface: { score: 2, hard_gate_at: 5, notes: "no air-gap requirement" }
exit_cost_days: { score: 2, hard_gate_at: 5, estimate_days: 2 }
columns:
hosted_free:
eligible: true
reason: "no hard-gate failures"
paid_hosted:
eligible: true
reason: "optional; no SLA demanded yet"
self_host:
eligible: true
reason: "optional; no control-surface 5"
recommendation: "keep_hosted_free"
exit_criteria:
- "data_gravity >= 5"
- "artifact_count >= 5"
- "no owner on expiry date"
- "revert rate measured and rising for two weeks"
And a tiny scorer you can run locally. It does not predict ROI. It only applies the knockouts and prints the remaining columns.
#!/usr/bin/env python3
"""Keep / buy / self-host switch. Conversation tool, not a verdict engine."""
from dataclasses import dataclass
HARD = 5
@dataclass
class Sheet:
data_gravity: int
failure_owner: int
named_human: str
review_load: int
workflow_coupling: int
control_surface: int
exit_cost: int
signed_data_path: bool = False
contract_controls: bool = False
def columns(s: Sheet) -> dict:
if s.failure_owner >= HARD and not s.named_human.strip():
return {
"hosted_free": False,
"paid_hosted": False,
"self_host": False,
"why": "no named owner — all columns ineligible",
}
free_ok = s.data_gravity < HARD and s.control_surface < HARD
paid_ok = (s.data_gravity < HARD or s.signed_data_path) and (
s.control_surface < HARD or s.contract_controls
)
self_ok = True # still requires an owner; staffing is a separate gate
why = []
if not free_ok:
why.append("hosted free knocked out by data gravity or control surface")
if not paid_ok:
why.append("paid hosted knocked out until contract matches controls/data")
if s.exit_cost >= HARD:
why.append("exit is expensive — you may pilot, you may not standardize")
return {
"hosted_free": free_ok,
"paid_hosted": paid_ok,
"self_host": self_ok,
"why": "; ".join(why) or "no knockouts; compare coupling and review load",
}
if __name__ == "__main__":
sheet = Sheet(
data_gravity=2,
failure_owner=3,
named_human="platform-lead-name",
review_load=3,
workflow_coupling=2,
control_surface=2,
exit_cost=2,
)
print(columns(sheet))
Run it:
python3 keep_buy_selfhost.py
You should see hosted free still eligible. Change data_gravity=5 and run it again. The free column should disappear. If it does not, your gate is theater.
Want a second check? Set named_human="" and failure_owner=5. Every column should go false. That is the whole point of field 2.
Where a free model path actually belongs
I only put a free hosted option in column A when I need a real alternative to “pay first” and “build a runtime first.” Otherwise the table collapses into a budget argument.
Open-source tools are useful here because you can inspect the workflow, not because the invoice is zero. MonkeyCode is one such project: it offers free model access and a free server option, which is enough to populate the hosted-free column and score it against paid seats and a self-hosted runtime. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
I am not going to invent model names, quotas, hardware, or benchmarks. Those claims go stale. The switch does not. If you cannot fill the six fields without marketing copy, you are not ready to standardize anyone's path—including this one.
If you need a concrete free column to score, put MonkeyCode in column A, then run the knockouts before you write it into onboarding.
Owner, expiry, exit
Every filled sheet needs four lines at the bottom. Skip them and you have a slide, not a policy.
- Owner: a named human who can stop the path, not a rotation alias.
- Expiry: a calendar date. I use 45 days for a keep-free recommendation. On that date you re-score or you archive.
- Archive rule: what happens to prompts, evals, and docs if you do not renew. “We'll remember” is not a rule.
- Exit criteria: the variable that reverses you. Write it as a threshold, not a feeling.
Example exit line I actually want on the sheet: “If workflow coupling reaches 5, or data gravity reaches 5, we stop onboarding and either sign a contract, self-host, or unwind.”
Sensitivity: what should reverse you?
Ask this out loud. Do not ask “would we buy?”
- If data gravity went to 5 next month, would you still keep hosted free?
- If exit cost went to 15 days because CI grew around the path, would you still call it a trial?
- If the named owner went on leave, would the path still be allowed?
- If review load stayed at 5 for two measurement windows, would you pay, self-host, or stop?
If none of those would reverse you, you already chose, and the scorecard is decoration.
Who should not use this
Skip this switch if you are a solo developer picking a personal tool. Six fields is ceremony.
Skip it if security needs a real threat model, DPIA, or vendor review. A 1–5 score is not that review.
Skip it if leadership already picked a vendor and wants a retrospective that looks like analysis. Garbage in, policy out.
Skip self-host as a fantasy column if you will not staff the runtime. A control-surface 5 with a failure owner of “the platform team, I guess” is how you create a weekend outage with extra steps.
And do not use the scorer as proof that free is cheaper. It cannot see review minutes, incident cost, or the political cost of unwinding a default tool.
What I would do in the next working session
Open the YAML. Fill it with one platform lead and one engineering manager in the room. Name the owner. Set the expiry. Run the Python knockouts live so nobody can average a 5.
Then pick one column. Keep hosted free, buy a contracted path, or self-host. Not two. A second path is a different decision, with a different cost of confusion, and it does not belong on this sheet.
Which single field, if it moved one notch, would reverse your current choice?
Top comments (0)