2026-08-27 · Updated 2026-08-27 · 8 min read
Avoid coding-agent vendor lock-in
A practical portability audit for teams adopting coding agents: find where lock-in actually concentrates across model, harness, and task truth, then verify four properties — open formats, Git-native task truth, exportable evidence, and switchable harnesses.
By Juno AI INC · vendor-lock-in · portability · yylo
Vendor lock-in with coding agents is not one decision you make when you pick a tool. It is a property that accumulates silently while the tools are working well: every task recorded, every workflow tuned, every session resumed makes the current arrangement feel cheaper to keep than to replace. The question that matters six months in is not "which vendor did we pick" but "which layers can we still swap, and where does our state live if any one of them goes away — or we stop paying for it."
This guide is the practical audit. First locate where lock-in actually concentrates, because the layers have wildly different exit costs. Then run a four-point portability checklist against your own stack — open formats, Git-native task truth, exportable evidence, switchable harnesses — and finish with a cheap exit test you can run today, while nothing is wrong and changing course still costs nothing.
Where lock-in actually concentrates
The harness boundary guide separates the stack into layers, and the swap costs differ by orders of magnitude between them. A model is a flag: re-run the same command with a different model selector and nothing else moves. An agent is a service selection, plus whatever tool surface it assumes. A harness is your accumulated configuration — extensions, skills, saved sessions — which may or may not travel to a competitor. And the control plane, the layer that holds task truth, evidence, and gates, is the one you cannot swap without moving history.
That layering explains why portability conversations go wrong. "We're locked in" usually means "our harness configuration is stuck" or "our task history lives in a store we don't control" — rarely "our model." The productive move is to stop arguing about vendors and name the layer: ask, for each layer, what the next run would cost if you changed it tomorrow, and where today's state would be left standing. The checklist below turns that into four verifiable properties.
The portability checklist
Four properties, each stated as a question you can actually check. Every claim about a tool's portability — including YYLO's — should be verifiable against these:
- Open formats — can you read your state without the product running? Every piece of durable state should be a format standard tools parse: Markdown, YAML, JSON, NDJSON. The failure mode it prevents: migration becomes a reverse-engineering project, so it never happens until it's forced.
- Git-native task truth — does the work history live in your repository? Tasks, decisions, dependencies, and responses should be files under version control in the repository you already back up. The failure mode it prevents: your process memory is hostage to an account, a plan tier, or a hosted board's retention policy.
- Exportable evidence — do you hold the run record? Runs should leave artifacts you can copy, archive, and grep without the vendor's product in the loop. The failure mode it prevents: you cannot audit or defend past work after you leave, so leaving means amnesia.
- Switchable harnesses — can the next run use a different agent or model? Selection should be per-run and cheap, and the system of work should not move when you swap. The failure mode it prevents: a vendor's pricing, model, or policy change becomes your migration project.
The rest of this guide works each check against YYLO's committed product documentation — not as the only acceptable answer, but as a worked example of what passing looks like in a real tool.
Check your formats are open
YYLO's durable state is deliberately boring. Hot task state is safe Markdown plus hash-chained ledgers; explicitly archived terminal tasks become immutable NDJSON packs. Workflows are YAML files you can read, diff, and lint before running. Skills are Markdown instruction files with YAML frontmatter. The operational scripts install as ordinary shell and Python files under .juno_task/scripts/, and configuration is a JSON file you can put under review. None of it requires a running service — or a network connection — to read.
That is the standard to hold any stack against, whatever you run: if the only read path for your task history is a logged-in web view, or the only export is a subscription feature, the formats are not open. Open formats are what make every later exit — backup, migration, audit, archival — a file-copy problem instead of a vendor negotiation.
Check your task truth is Git-native
Task truth is where lock-in hurts most, because it is the layer with the longest memory. YYLO Ledger preserves task truth in Git: tasks, statuses, responses, and commit references live in the repository, so git log is the audit trail and your existing backup story already covers the history. Every product change implements in a dedicated task worktree, which keeps concurrent agents isolated without forking the truth. Cross-project routing is disabled by default and must be authorized explicitly with named projects, and invalid routing never falls back silently — task data cannot leak into a store you did not declare. The introductory treatment of task truth as durable agent memory owns the full story.
The audit question for your stack: if you deleted every agent tool tomorrow, would the repository still tell the story of what was attempted, decided, and landed? If the answer requires a hosted board the repository cannot read offline, the truth is not yours — it's rented.
Check your evidence is exportable
Evidence is the record of what actually happened, and it only counts as yours if you can pick it up and move it. YYLO runs write durable artifacts to disk: a run directory with a manifest of statuses, exit codes, and session ids, plus per-step stdout, stderr, and response files. For audited automation, yy pi --execution-envelope emits one juno_execution_envelope.v1 JSON object as the sole stdout payload, and its provider, model, session, version, and cost fields come from marked backend terminal evidence rather than the agent's own prose. Session history appends to a session_history.json file under a Git-common-dir state root outside the tracked product tree — with an explicit location override — recording each run's initial prompt, subagent, model, settings, cost, and session ids.
All of it is plain files. You can tar a run directory, grep a manifest, hand an envelope to an auditor, or move the whole evidence tree to another machine. The full artifact map and recovery contracts have their own guide; the portability point is narrower: the record of the work never lived inside the tool, so the tool leaving changes nothing about the evidence.
Check your harnesses are switchable
The last check is structural: the system of work should sit above the harnesses, not inside one of them. YYLO drives installed agent CLIs from the control plane — the -s/--subagent flag documents claude, codex, gemini, pi, and cursor, and -m selects the model behind the service, resolved in a fixed order: the CLI flag first, then the configured per-service default, then the built-in default. Custom services are ordinary Python scripts in ~/.yylo/services/ that accept -p/--prompt, -m/--model, and -v/--verbose and emit JSON events to stdout — no vendor relationship required to add one.
The consequence is that swapping is a flag on the next run, not a migration: task truth, evidence, and gates stay exactly where they were while the agent, model, and harness underneath change per run. That is the property to demand from any stack. When orchestration state lives inside one harness — its session store, its proprietary project format, its account — every model comparison, agent evaluation, and vendor negotiation inherits the harness's constraints. The YYLO documentation is the operational reference for the service and model flags.
Run the exit test before you need it
Portability claims are cheap to make. Three drills turn them into evidence, and each one is a bounded command you can run today:
- Drill 1 — swap the layers for one run. Re-run a small task with a different service and model —
yy start -b shell -s pi -m :sonnet -i 1 -v— and confirm the task truth and run artifacts land in the same places as before. This proves harness switchability without migrating anything. - Drill 2 — read your history without the product. Open the task files in an ordinary editor and run
git logon the repository. If you can reconstruct what happened with tools that have no relationship to the vendor, formats and task truth pass. - Drill 3 — move the evidence. Copy one run directory — or the session-history state root — to another machine and read the manifest and step artifacts there. Evidence that survives the move is evidence you own.
Run these while nothing is wrong. A drill that fails has just found your lock-in while it still has no leverage over you; a drill that passes has converted a marketing claim into an observation. The habit of starting bounded is what keeps each drill a one-command experiment instead of an incident.
Start bounded, stay portable
The smallest unit that exercises all four properties is one bounded, evidence-producing task, and YYLO's own installation passes the checklist it asks you to run: an npm package with reviewable source, state in Markdown and Git, evidence as files on your disk, and per-run agent and model selection.
The three products are separately installable and separately removable — YYLO from npm, YYLO Ledger from PyPI, YYLO Benchmark from npm, each with its own repository — so even the control plane composes instead of bundling. Install it, run one bounded task, and check where every artifact landed. If you ever decide the stack is wrong for you, that same inventory is your exit map: the repository keeps the truth, the files keep the evidence, and the next harness is one flag away.