Skip to content

Wrapper mode

agedum --wrapper <harness> [--sandbox] [--rw-dir DIR]... [--dry-run] -- <command> [args...]

Wrapper mode runs any command inside a private mount namespace where the agent-neutral source has been compiled to the chosen harness's native layout and injected at the paths that harness already reads. It is the low-level entry that provider mode (agedum <name>, the normal way to launch) builds on — provider mode is wrapper mode plus a resolved provider environment.

Reach for --wrapper directly only to front a harness with the injected context but no provider env — e.g. native Claude with your own login — or to inspect what gets injected with --dry-run.

agedum --wrapper claude   -- claude -p "…"     # render for Claude, run claude
agedum --wrapper kimi     -- kimi -p "…"       # render for kimi, run kimi
agedum --wrapper opencode -- opencode run "…"  # render for opencode, run opencode
agedum --wrapper cline    -- cline task "…"    # render for Cline, run cline

Context and command are decoupled

The invocation has two halves split by a literal --:

  • before ----wrapper <harness> picks the format to compile to (claude / kimi / opencode / cline / reasonix / aider / pi / codex), plus the optional --dry-run.
  • after -- — the command, run verbatim, including its own binary and flags. agedum does not parse or rewrite it (a harness may get extra flags appended — see its page). --wrapper=claude is also accepted; an unknown harness or option is an error.

So the flag chooses what context the process sees, and everything after -- is yours.

How a harness resolves the source

Each --wrapper <harness> selects a compiler. A compiler renders the project and global scopes into the harness's native layout and produces a plan: a set of (compiled-file → mount-target) binds, plus any extra arguments to append to your command. The launcher injects the binds into the namespace and runs the command. Every harness disposes of each source in one of three ways:

Disposition Meaning
injected (→ <dest>) agedum writes a compiled copy and binds it at the path the harness reads (e.g. Claude's CLAUDE.md, every harness's skills dir).
read in place the harness reads the file natively at its source location, so agedum injects nothing — and cannot, since the root AGENTS.md is git-tracked. kimi, opencode, cline, reasonix, and pi all read the project AGENTS.md this way.
appended flag the context is passed as an extra argument, not a bind — aider's --read for both scopes' instructions (aider reads no AGENTS.md natively).

Two rules hold for every harness:

  • Each scope lands at its own native location — the project and global sources are never concatenated into one file. The harness reads both and applies its own precedence, exactly as if you had authored them by hand. See Scopes.
  • Per-harness overlays are applied — for skills, the base SKILL.md is merged with an optional SKILL.<harness>.md; for the global AGENTS.md, an optional sibling AGENTS.<harness>.md is merged on. An overlay for a different harness is skipped.

The exact binds, targets, and any appended flags differ per harness — that is what each harness page documents:

Harness Wrapper resolution Provider config
Claude details details
kimi details details
opencode details details
Cline details details
reasonix details details
aider details details
pi details details
codex details details

Inspect without running — --dry-run

Put --dry-run before -- to compile the source and print the plan — the bind targets and any appended args — without launching:

agedum --wrapper claude --dry-run -- claude   # list the injected virtual files, don't run

The output groups the dispositions by scope (project / global); the same view provider mode shows, minus the resolved environment. With --sandbox, it also lists the writable set (see below).

Filesystem sandbox — --sandbox

By default the launched command shares your whole filesystem read-write — the mount namespace isolates only what the harness reads as config, not where it can write. Pass --sandbox to switch to write-confinement: the host is mounted read-only, and the command can write only to

  • the project root — the working tree it was launched in;
  • the harness's own state/config dir — so it can persist sessions, settings, and auth (e.g. ~/.claude for Claude Code, ~/.cline for Cline, ~/.codex for Codex); agedum knows each harness's dir and grants it write access (creating it if missing), whether or not the harness injects anything under it;
  • the nearest existing ancestor of every file agedum injects (so bwrap can create the mount point);
  • a private /tmp (a fresh tmpfs, discarded on exit);
  • any directory you add with --rw-dir DIR (repeatable; passing it implies --sandbox). A DIR holding a shell glob (*, ?, […]) is expanded to each existing match, so --rw-dir '~/src/*' makes every immediate subdirectory of ~/src writable.

Everything else on the host stays readable but cannot be modified, so an autonomous agent cannot alter or delete files outside its working set.

agedum --wrapper claude --sandbox -- claude -p "…"            # confine writes to the project
agedum --wrapper claude --rw-dir ~/scratch -- claude -p "…"   # + a writable scratch dir

--dry-run prints the resolved writable set under a sandbox · write-confinement heading, so you can see exactly what the command will be able to write before launching. A --rw-dir that already lives inside the project root is folded in — a parent bind covers it.

This confines the filesystem only: the network is untouched, so the harness still reaches its model endpoint. Like all of wrapper mode it is Linux-only and relies on bwrap.

No footprint

Nothing is written to your real tree or $HOME: the compiled files live only inside the launched process's mount namespace, and agedum refuses to overlay a git-tracked path. Wrapper mode is Linux-only and needs bwrap (bubblewrap) on PATH.

Behaviour when no source is found

If neither the project nor the global scope has any AGENTS.md or skills, agedum prints a warning to stderr and still runs your command — just with nothing injected. It never blocks the launch on an empty source.