codexport
v0.6.0
Published
sync a canonical Codex setup from one master machine to follower machines
Maintainers
Readme
codexport replicates a canonical master Codex setup to follower machines. it is built for operators who want one trusted ~/.codex source of truth, follower-local overlays, and a low-friction npx join path without committing plaintext secrets to GitHub.
the master serves a content-hashed bundle from its ~/.codex directory. followers pin the master's fingerprint on join, fetch updates over a Tailscale-reachable HTTP address, and apply updates at Codex SessionStart through a short best-effort hook.
MCPs are exported as full definitions, including explicit per-MCP env entries. command-based MCPs are written through a quiet local managed launcher, so followers run node ~/.codexport/bin/codexport-mcp-run.mjs mcp run <name> and let codexport translate master-local paths into portable npm, uv, or source artifacts when the master command shape can be inferred.
why
if you keep a carefully tuned Codex setup on one machine and want the same defaults elsewhere, codexport gives you a practical pull-based sync path.
- keep the master as the canonical Codex configuration source
- let followers preserve local MCPs, local skills, trust entries, and path overrides
- sync auth-bearing files through the private Tailscale path instead of a plaintext GitHub commit
- export every master MCP definition instead of dropping machine-local entries
- hydrate inferred MCP artifacts on followers through npm, uvx, or copied local source trees
- refresh followers at Codex session startup without interrupting active sessions
- use content-hash revisions and pinned master fingerprints instead of blind file copies
quickstart
codexport requires Node.js 20+.
on the master:
npx codexport master init
npx codexport master service install
npx codexport master link --host master.example.ts.neton a follower:
npx codexport follower join "codexport://join?host=master.example.ts.net&port=17342&fingerprint=..."
npx codexport hook installmanual sync remains available:
npx codexport sync --apply
npx codexport statussync model
flowchart LR
subgraph master["master machine"]
masterCodex["~/.codex canonical state"]
masterCli["codexport master serve"]
masterBundle["content-hashed bundle"]
end
subgraph privateNet["tailscale network"]
http["http://master.example.ts.net:17342"]
end
subgraph follower["follower machine"]
localOverlay["~/.codexport local overlay"]
sessionHook["Codex SessionStart hook"]
generatedCodex["generated ~/.codex"]
end
masterCodex -->|select files and hash content| masterBundle
masterBundle --> masterCli
masterCli -->|serve bundle and fingerprint| http
sessionHook -->|check revision before session| http
http -->|download changed bundle| sessionHook
localOverlay -->|merge MCPs, skills, path variables| sessionHook
sessionHook -->|backup and apply| generatedCodexfollowers trust the provided Tailscale address and store the master fingerprint. later syncs refuse changed fingerprints by default, so a changed master identity requires intentional re-enrollment.
trust flow
sequenceDiagram
participant Operator as operator
participant Master as master
participant Follower as follower
participant Codex as codex session
Operator->>Master: codexport master link
Master-->>Operator: join link with host, port, fingerprint
Operator->>Follower: codexport follower join "codexport://join?..."
Follower->>Master: GET /meta
Master-->>Follower: fingerprint and revision
Follower->>Follower: pin trusted fingerprint
Follower->>Master: GET /bundle
Master-->>Follower: content-hashed bundle
Follower->>Follower: apply bundle plus local overlay
Codex->>Follower: SessionStart hook
Follower->>Master: check revision and fingerprint
Follower-->>Codex: continue with latest applied configincluded state
the master bundle includes canonical Codex config, auth files, hooks, prompts,
rules, skills, skill libraries, AGENTS.md, RTK.md, and mise.toml when
present.
runtime state such as logs, caches, sessions, history, compact handoffs, and SQLite databases is excluded.
MCP export and repair
all master MCP definitions are exported into ~/.codexport/mcp-manifest.json on followers. generated command MCP entries in ~/.codex/config.toml point at the managed launcher:
[mcp_servers.example]
command = "node"
args = [ "~/.codexport/bin/codexport-mcp-run.mjs", "mcp", "run", "example" ]when Codex starts an MCP, codexport mcp run reads the original manifest entry, restores transferred environment values, rewrites master paths to follower paths, and chooses a runnable target. the master also exports MCP artifact metadata when it can infer the command shape:
| source shape | follower action |
| --- | --- |
| npm package shims or node .../node_modules/... | install and run the inferred npm package/bin |
| Python uv tool shims | run with uvx --from <package-or-url> <binary> and install uv when missing |
| editable/local Python uv tools | copy the source artifact to ~/.codexport/mcp-artifacts and run it with uvx --from <artifact> |
| local Node package source | copy the source artifact to ~/.codexport/mcp-artifacts, install production deps, and run the original entrypoint |
| URL MCPs | keep the URL config unchanged |
unsupported local binaries are still kept in the manifest and generated config. if a follower cannot repair one, startup fails with the missing tool and repair step instead of silently removing the MCP. large runtime payloads are not embedded in source artifacts; they must be installable or reachable from the follower.
by default codexport exports env values already present in the MCP config. if a required secret only exists in the master process environment, opt it in explicitly before rebuilding the master bundle:
CODEXPORT_EXPORT_ENV=SEARCH_API_KEY,ANOTHER_TOKEN codexport master rebuildthere are no built-in MCP-name adapters. if a command cannot be inferred from its real npm, uv, or source shape, it runs as declared after path rewriting and logs the exact failure under ~/.codexport/logs/mcp/<name>.log.
local follower state
follower-local state lives under ~/.codexport:
~/.codexport/local.toml
~/.codexport/mcps.local.toml
~/.codexport/skills/
~/.codexport/overrides/canonical MCP and skill names win by default. same-name local MCPs or skills
fail unless explicitly allowed in local.toml:
allowMcpOverrides = ["local-name"]
allowSkillOverrides = ["local-skill"]
[pathVariables]
workspaceRoot = "D:/workspace"path variables in canonical config such as ${workspaceRoot} are expanded from
the follower's local.toml before writing the generated ~/.codex/config.toml.
command surface
| command | purpose |
| --- | --- |
| codexport master init | create or refresh the master identity and bundle state |
| codexport master serve | serve the current canonical bundle over HTTP |
| codexport master link | print a durable follower join link and fallback command |
| codexport master rebuild | force rebuild the master bundle for repair/debugging |
| codexport master service install | install the user-level master background service |
| codexport follower join | enroll a follower from a join link or explicit master URL |
| codexport sync | fetch the latest master bundle |
| codexport apply | apply the last staged bundle |
| codexport mcp run <name> | run or repair a synced command MCP from the follower manifest |
| codexport hook install | install the follower-only Codex SessionStart hook |
| codexport status | report role, master URL, fingerprint, revision, and reachability |
platform support
| platform | master service | follower hook | manual sync | | --- | --- | --- | --- | | linux with systemd user services | supported | supported | supported | | windows 10/11 scheduled tasks | supported | supported | supported |
followers do not need a background service in v1. the hook runs a short best-effort sync at Codex session startup, and codexport sync --apply is available when an immediate refresh is needed.
examples
generate a copy-paste join command:
codexport master link --host master.example.ts.netjoin with explicit trust metadata:
codexport follower join \
--master http://master.example.ts.net:17342 \
--fingerprint <fingerprint> \
--applycheck current follower state:
codexport statusdevelopment
npm install
npm run typecheck
npm test
npm run build
npm pack --dry-run