Phase 5
August 10, 2026 · View on GitHub
Status: investigation (2026-08-10). Dep facts read from apps/*/mix.exs and grepped call
sites against the tree at the time of writing. The coding_agent-blocker resolution below is a
proposed decision (needs user sign-off) — actually extracting a repo is a larger commitment
than the boundary work of Phases 1–4, so this document names and prices the blocker rather than
resolving it unilaterally.
This is the missing piece the §5 Phase 5 checklist assumed away: it lists a per-repo procedure
(5.1–5.7) but never states which product groups are ready to run it. The round-2 sweep
found that they are not equally ready — lemon-sim has a clean published-only dependency profile
while coding-agent is blocked on two unpublished apps — so the two are not interchangeable in
the extraction order.
1. Method
The nine published packages (post-D13) are:
ai → lemon_ai, lemon_core, agent_core → lemon_agent, lemon_memory, lemon_media,
lemon_router, lemon_gateway, lemon_channels, lemon_platform_test.
Everything else in apps/ is either a reference-runtime app (stays in the platform repo,
unpublished: lemon_control_plane, lemon_cli, lemon_web, lemon_automation, lemon_skills,
lemon_browser, lemon_lsp) or a product app slated to leave (coding_agent,
coding_agent_ui, lemon_mcp, lemon_evals, lemon_sim, lemon_sim_ui, lemon_tcg), plus the
x_api satellite (D7).
An app is extraction-ready iff every one of its in_umbrella deps is either (a) a published
package, or (b) another app in the same product group (which leaves in the same git filter-repo
and stays an in-repo dep). Any in_umbrella dep on a reference-runtime app that stays behind is a
blocker: after extraction it would have to resolve from hex, and there is no hex release.
2. Per-product-group readiness
| Product group | App | in_umbrella deps | Blocker (unpublished dep) |
|---|---|---|---|
| lemon-sim | lemon_sim | lemon_core, agent_core, ai | none |
lemon_sim_ui | ai, lemon_core, lemon_sim | none (sim is intra-group) | |
lemon_tcg | lemon_core, agent_core, ai, lemon_sim | none (sim is intra-group) | |
| coding-agent | coding_agent | agent_core, ai, lemon_core, lemon_gateway, lemon_memory, lemon_platform_test*, lemon_skills, lemon_browser | lemon_skills, lemon_browser |
coding_agent_ui | coding_agent, lemon_core | none (coding_agent is intra-group) | |
lemon_mcp | coding_agent, lemon_core, agent_core, lemon_skills | lemon_skills | |
lemon_evals | agent_core, ai, coding_agent, lemon_core, lemon_skills | lemon_skills |
* lemon_platform_test is a only: :test, runtime: false dep — the same test-only dependency
direction a third-party engine author has; not a runtime blocker.
lemon-sim is ready now. Every platform dep it touches is published; the only cross-app deps
inside the group (sim_ui → sim, tcg → sim) travel together in the extraction and remain in-repo
deps afterward. This confirms the D8 premise: sim has the cleanest profile and should be the
first product extracted — which means the §5 Phase 5 order (coding-agent first) is backwards
and should be flipped (see §5).
coding-agent is blocked on two reference-runtime apps, lemon_skills and lemon_browser.
lemon_mcp and lemon_evals inherit the lemon_skills blocker; coding_agent_ui is clean once
coding_agent itself moves.
3. Anatomy of the blocker
lemon_skills — large, clean-deps, shared, tool-heavy
- Size: 19,442 LOC (
apps/lemon_skills/lib). Not a leaf — it is the skill discovery / MCP-source / lockfile / installer / synthesis subsystem plus the agent tool implementations. - Its own deps are all published:
lemon_core,lemon_memory,lemon_media,agent_core,ai. After D7 moved the three X tools out, it has zero unpublished deps — so it is itself publishable-clean. The blocker is not that skills can't be published; it's whether we want to commit to semver on a 19k-LOC surface. - coding_agent's coupling is deep and wide: 24 references across 8 files, ~20 distinct
LemonSkills.*modules — including live agent tools (Tools.MediaAnalyzeImage,MediaGenerateImage/Speech/Video,MediaStatus,MediaTranscribeAudio,Memory,MemoryTopic,SearchMemory,Kanban,ReadSkill,SkillManage) and prompt/relevance surfaces (Config,find_relevant,PromptView.render_relevant_skills,SkillView.from_entry,McpSource.discover_tools). This is load-bearing, not incidental. - It is shared infrastructure, not product code. Besides the coding-agent group
(
coding_agent,lemon_mcp,lemon_evals), it is consumed by the reference runtime:lemon_control_plane(25 refs) andlemon_automation(4 refs). The singleCodingAgentreference insidelemon_skillsis a moduledoc comment (prompt_view.ex:91), not a real reverse edge — so skills does not depend back on the product, but the runtime does depend on skills.
lemon_browser — tiny, clean, leaf
- Size: 818 LOC. Deps:
lemon_core+jasononly — a leaf. - coding_agent's coupling is shallow: 3 references, all in one file
(
coding_agent/tools/browser.ex), 3 modules:LemonBrowser.Artifacts,.LocalServer,.RoutePolicy. - Also shared with the runtime:
lemon_control_plane(5 refs). No reverse edge to CodingAgent.
4. Options and cost
The decisive fact for all four options is that both skills and browser are shared between the coding-agent product and the reference runtime that stays behind. They are platform infrastructure that the product happens to use, not product-owned code. That kills the "they leave together" option and shapes the rest.
(a) Publish lemon_skills + lemon_browser as packages 10 & 11.
Both are clean (published-only deps), so the tarball mechanism (hex_package.exs) works with no
inversion. lemon_browser is trivial: 818 LOC, leaf, low API-churn risk — publishing it is one map
entry and metadata, on par with the D13 lemon_media decision. lemon_skills is the real cost: a
19k-LOC surface (discovery, MCP sources, lockfiles, installers, synthesis) whose API still churns;
publishing commits us to semver on all of it, and 4.4-style changelog discipline on every change.
Viable, and the only option that doesn't add indirection, but it enlarges the published surface
substantially and needs an API-stabilization pass on skills first.
(b) Vendor / invert behind a behaviour (the RuntimeModules / EngineInfoBridge pattern).
For lemon_browser this is cheap and clean: 3 modules behind one configured runtime module, exactly
the shape already used for doctor/media/lsp. For lemon_skills it is prohibitive: coding_agent
consumes ~20 modules including a dozen concrete agent tools; a behaviour that fronts all of that is
not a seam, it's a re-export of the whole app. Attractive for browser, a non-starter for skills.
(c) Extract coding_agent with skills + browser as a larger product repo.
Not viable. lemon_control_plane and lemon_automation (reference runtime, staying in the
platform repo) both depend on lemon_skills, and control_plane depends on lemon_browser. If
those apps leave with coding_agent, the reference runtime breaks and would itself need skills/browser
inverted or published — i.e. you land back in (a)/(b) plus a broken runtime in the interim.
(d) Defer coding_agent extraction until external demand, keeping it in the umbrella.
Zero cost now; coding_agent is not the flagship (sim is, D8), so nothing forces its extraction on
the Phase 5 timeline. The umbrella keeps building it against in_umbrella deps exactly as today.
5. Recommendation
Two-part, argued from the asymmetry in §3:
-
Extract
lemon-simfirst (unblocked flagship), notcoding-agent. Flip the §5 Phase 5 order. Sim is ready today (§2), it is the D8 flagship, and running the5.1–5.7procedure on the clean case first de-risks the tooling (git filter-repo, CI port, nightly integration lane) before the hard case. -
For the coding-agent blocker, split the two deps by their cost:
lemon_browser: publish it as a package (cheap, clean, leaf — same rationale as D13 forlemon_media). Inversion (b) is also fine here and slightly smaller-surface, but publishing is more honest since control_plane consumes it too and a package serves both.lemon_skills: publish it as a package as well (option a), gated on an API-stabilization pass, and defer coding-agent's extraction until that pass lands. Reject invert (b) — the 20-module, tool-heavy surface makes a fronting behaviour a re-export, not a seam. Reject leave-together (c) — the reference runtime needs skills. Skills is genuine shared platform infrastructure with clean deps; the only real question is committing to its API, so the work is stabilization, not architecture. Until that lands, defer (d) coding-agent — it is not the flagship and nothing on the timeline forces it.
Net: sim extracts on the current Phase 5 tooling now; browser and skills become published packages 10 & 11 when coding-agent's turn comes; coding-agent, mcp, evals, and coding_agent_ui follow once skills' API is release-worthy. This keeps the "publish, don't invert, for shared clean-dep infrastructure" principle consistent with D13, and avoids bolting a 20-module behaviour onto the product boundary.
6. Open items this surfaces
- Package count grows from 9 to 11 if the recommendation is accepted (
lemon_skills,lemon_browserjoin). Both need the 4.1 metadata treatment (hex_package.exswrapping, CHANGELOG, LICENSE, docs) and a slot in the 4.3 publish order (after their deps: browser after core; skills after media/memory/agent). lemon_skillsAPI-stabilization is now a named prerequisite for coding-agent extraction, not a hidden one. Scope: the ~20 modules coding_agent/mcp/evals consume (§3) are the public surface that has to settle; the installer/lockfile/synthesis internals can stay@moduledoc false.- Hex-name availability for
lemon_skills/lemon_browsernot yet verified (E4 checked the original 8 + media). Verify before reserving.