epic: agent-config portability — onboard an arriving Claude Code / Codex user, and let them leave as cheaply as they arrived
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 152
- Forks
- 16
- Avg merge
- 14h 48m
- Merged PRs (30d)
- 536
Description
epic: agent-config portability — onboard an arriving Claude Code / Codex user, and let them leave as cheaply as they arrived
Tracking issue. The work is in the sub-issues; this issue owns the shared map, the boundaries
every sub-issue inherits, and the sequencing.
Why
Codex's desktop app ships one-click "Import other agent setup": scan for a Claude Code
install, preview, cherry-pick ~8 categories, convert (CLAUDE.md → AGENTS.md,
settings.json → config.toml, skills re-homed under .codex/, 30 days of sessions,
subagents → .codex/agents/*.toml), then open a follow-up agent thread for whatever the
importer refused. It works because it attacks the actual adoption blocker: sunk cost. A
team with two quarters of skills, agent defs, rules and permission policy hears "try another
harness" as "re-derive all of that."
Mecatl's position is structurally different and we currently fail to say so: Codex's importer
converts and takes ownership, so the switching cost merely moves. Mecatl reads .claude/**
natively, in place, without conversion — so a user can run Claude Code and mecatl against
the same repo, same rules, same skills, in parallel and indefinitely. Evaluation is nearly
free and adoption is reversible. What's missing is not capability; it's the front door and an
honest account of what we do and don't honour.
The shared map — what mecatl does with a Claude Code setup today
Every sub-issue works against this table; corrections here propagate down.
| Artefact | Status today | Where |
|---|---|---|
CLAUDE.md at workspace root |
active (AGENTS.md fallback) | engine/prompt/builder.go:306-324 |
nested CLAUDE.md, @path imports |
not loaded (root-only) | same |
.claude/rules/** |
active | engine/adapter/rulesfs/resolve.go (#329) |
.claude/agents/*.md |
active (--agents-conventional, on) |
cmd/mecated/main.go:1455 (#328) |
.claude/skills/*/SKILL.md |
supported, off by default (--skills-conventional) |
cmd/mecated/main.go:1448 |
.claude/commands/*.md |
supported, off by default (--enable-commands) |
cmd/mecated/main.go:1470-1471 |
.claude/settings{,.local}.json permissions |
supported, off by default and lossy (--import-claude-permissions) |
main.go:1491, permconfig/resolve.go:29-43 |
~/.claude/projects/**/*.jsonl sessions |
one at a time, path supplied by hand | cmd/mecated/import.go, ADR 0099 |
Claude settings.json hooks |
no config lane — global hooks are Go-composed, rebuild required; only agent-def hooks: is config-driven |
docs/usage/hooks.md |
mcpServers (.mcp.json, ~/.claude.json) |
stdio unsupported by design — streamable-HTTP only, so most real blocks cannot transfer | engine/adapter/agentfs/discover.go:121 |
| plugins / marketplace | not supported | — |
Two consequences worth stating plainly, because they bound the whole epic: three of the most
valuable categories are already live with no action at all (instructions, rules, agent defs),
and two categories genuinely do not carry over (global hooks, stdio MCP). Any pitch that
implies otherwise is false; the product move is to report them honestly.
Boundaries every sub-issue inherits
- Read
.claude/**in place; do not convert it..claude/**stays authoritative.
Copying into.mecatl/**is always opt-in, never the default. Nothing is rewritten into a
mecatl dialect. - No secrets move. Env values, tokens and API keys are never copied and never printed;
MCP servers needing credentials are reported, with the field blank. - Offline. No provider credential, no running daemon, no network (ADR 0099's posture).
- ADR 0099's guards stay load-bearing wherever files are written: no overwrite, no symlink
follow, no.git, name sanitization, destination confinement. - Trust posture untouched. Imported project ALLOW rules still require
--trust-project;
skills/agents/commands remain the same trust class asAGENTS.md. Migration must not become
the hole unreviewed model-steering content arrives through. settings.local.*is personal. A*.localsource never contributes to a shared,
checked-in destination.
Sub-issues
- A (#411) —
mecated migrate --scan-only: read-only inventory and report. Renders the table
above for this configuration in three buckets (active now / available, needs this flag /
not supported, with a reason). Writes nothing. Ships most of the onboarding win at
essentially zero risk, and is a prerequisite for D. - B (#412) — batch session discovery over
~/.claude/projects/**. Blocked on four decisions
named in the issue: dedup key (sessionId, not the path hash atimport.go:184),
skip-existing instead of the hard error atimport.go:209, what to do with dropped
isCompactSummaryrecords (transcript.go:155), and a context bound on resume. Carries the
plaintext-duplication and retention-off-by-default requirements. - C (#413) — reviewable permissions artefact. The runtime import's lossy demotions exist only in
stderr today, which no policy owner can sign off. One generated file, in one lane, every
demotion commented with its reason. - D (#414) —
mecatuizero-state/migrateoverlay. Renders A's report at the point of arrival,
optionally seeding a follow-up session with the "not supported" list so the agent finishes
the job conversationally (Codex's follow-up-thread trick). After A. - E (#415) — export: emit mecatl artefacts in Claude-Code-shaped layout. The credibility item.
mecated importexists; nothing goes the other way, so "adoption is reversible" is not yet
an honest claim. Two-way portability is what makes the portability argument provable rather
than rhetorical.
Sequencing
A (#411) first, alone. B (#412) and C (#413) carry real design questions and must not ride along on a read-only
reporting change. D (#414) after A. E (#415) is independent and is the item that makes the parent claim
true — schedule it, don't let it drift.
Out of scope for the epic
Reversing the HTTP-only MCP stance, or adding a config lane for global hooks. Both are
prerequisites someone might infer from "migrate everything" — they are separate architectural
decisions, and until they're made, A reports those categories as unsupported with the reason.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Begin with sub-issue #411, since the epic sequences the read-only scan first. Read the shared artefact map and the referenced paths in engine/prompt/builder.go, engine/adapter/rulesfs/resolve.go, cmd/mecated/main.go, and internal/adapter/permconfig/resolve.go. Done means a scan-only inventory reports active, available, flag-dependent, and unsupported categories without writing files.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- cli, developer-experience
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100