Skill, Preset, and Self-Modification
cordis_define lets an Agent rewrite its own runtime while running. Core directories: packages/extensions/tool-cordis/ and apps/cli/config/agent-presets/.
cordis_define and cordis_run to grow new tools for itself at runtime, and where this self-modification trust boundary is drawn; and how the preset layer shadows the global layer in the layered skill registry.
Scene: in a Creative mode (cordis preset) session, the user says “Build me a tool that counts lines of code.” Left is live runtime state; right is the Agent’s actions — follow the captions through once.
Plugin registry (Plugin / Package)
Tool catalog
Agent actions
packages/extensions/tool-cordis/src/index.ts (lines 148–259), verified on 2026-08-13.First, dissolve the launch-post suspense: Standard, Code, Minimal, and Creative — four modes, and you won’t find a single mode-branch line in the source. Under apps/cli/config/agent-presets/ sit four directories, each with one agent.cordis.yml; one file describes one plugin composition, mounted on one session. Minimal mode is 62 lines total: a persona that says “You are a helpful software engineer assistant.” plus complete: true (refuse any later assembly that stuffs more into the prompt), tools are only persistent bash and an editor, not even compaction — a config for running benchmarks. Creative mode is Standard mode unchanged, plus three extras: the self-referential toolset tool-cordis, a skill that teaches writing compositions, and a persona that teaches the model to tell the two planes apart.
The two planes are this system’s coordinate frame. The HOST composition holds what is shared across sessions: persistence, sandbox and approval, model routing, the subagent registry. AGENT PRESET holds what one session contributes to those registries: its tools, persona, prompt segments. One detail shows how finely the boundary is drawn: a service-publishing line in a preset either belongs to the host or is wrapped in an isolate realm. Minimal mode wants an unsandboxed local filesystem, so it wraps fs-local in its own realm, shadowing only that session’s fs; other sessions still go through the sandbox (minimal/agent.cordis.yml lines 46–57).
Skills are layered too. The global layer holds deployment-registered ones (repo plugins); the preset layer holds ones that travel with the preset. On read, a nearer same-named entry wins outright; sort weight only applies within one layer. Creative mode’s editing-cordis-compositions skill lives in the preset directory, copied and edited with the preset — the yml comment explains why: it describes this deployment’s two planes, and the preset is the unit that gets copied (cordis/agent.cordis.yml lines 248–254). The design notes also explicitly rejected cross-layer merge-and-sort; shadowing must be clean, or the model seeing two same-named skills won’t know what to do (.agents/notes/implemented/architecture/2026-08-09-layered-skill-registry.zh.md).
define does not executecordis_define only validates parameters and syntax, records the source as an immutable Package — no approval request, no execution, no move of currentPackageId. To make it run, you call cordis_run again. Define and activate stay separate, so a bad change still has something to roll back to.
failure leaves the pointercordis_run switches currentPackageId only after full success; on startup failure the old current stays put. Version changes use kind:"existing" to append a new Package; old versions are kept forever — rollback is just running an old ID.
the boundary is trustCreative mode’s file header, verbatim: “Treat a session on this preset as shell access.” Model-written JS runs against the live runtime with no sandbox safety net; the defense is who may use this preset — the code itself puts up no fence.
First piece of evidence: Creative mode YAML’s file header. The first eight lines say what it is: Standard mode plus a self-referential toolset. The last four are the trust statement, putting “treat as shell access” into the config file’s comments:
# The `cordis` agent preset: the standard coding agent, plus the ability to
# read and write the runtime it is running in.
#
# It exists so a person can ask an agent to author another agent. Everything in
# `standard` is here unchanged; what is added is the self-referential Cordis
# toolset, a skill that teaches composition authoring, and a persona that says
# which of the two planes an edit belongs to.
#
# TRUST: `cordis_mount` evaluates model-written JavaScript against the live
# runtime, and a composition this agent writes becomes a preset other sessions
# mount. Treat a session on this preset as shell access — the toolset's own
# documentation makes the same statement.
apps/cli/config/agent-presets/cordis/agent.cordis.yml, verified on 2026-08-13. Code blocks keep the original source text.Second piece of evidence: how the skill registry merges on read — clear without pasting code. collectFresh lines up every layer: global first, then the preset scope chain with distant ancestors earlier and the local layer last. It then pours each layer’s entries into one Map keyed by skill name. A Map’s nature is last-write-wins, so a nearer same-named entry automatically replaces a farther one; shadowing is one Map.set, with no cross-layer weight comparison. The function-header comment aligns this rule with the tool registry’s shadowing rule, and adds: sort weight only applies to duplicates within the same layer.
Source: collectFresh at packages/skill/skill/src/index.ts lines 552–566, verified on 2026-08-13.
Two more mechanisms worth remembering — sources noted here. First, when a dynamic plugin reshapes the toolset mid-flight, the session log records the full post-change request headers, keeping the “what the model sees ⟺ what’s in the log” invariant (.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md). Second, the persona forbids the Agent from editing shipped preset directories: upgrades overwrite them wholesale, and breaking the cordis preset is turning off your own mode by hand — to change it, copy out and edit the copy (cordis/agent.cordis.yml line 27).
Claude Code defines a role with one markdown file plus frontmatter: description, available tools, model — and AgentTool call args can temporarily override the frontmatter model field (manuscript study/chapters/05-multi-agent.md lines 32–38 cite AgentTool.tsx’s inputSchema). Skills work the same: one directory, one SKILL.md. This path is “config describes a role”: how a role can differ depends on which fields the framework opens in frontmatter.
DSH’s preset is “a whole plugin composition as a role”: persona is just an ordinary plugin line in the composition, peers with tools, compaction policy, and the subagent backend. Minimal mode can even swap the entire filesystem implementation and turn off compaction — depth of differentiation frontmatter fields can’t express. The cost is blunt: writing a preset means understanding two planes and isolate realms, a much higher bar than writing markdown, which is why Creative mode carries a teaching skill plus a cordis_inspect_query that can read the runtime. One side is a low-bar role card; the other is a full-power composition language — the two disagree on who is supposed to author roles.
Work through two boundary scenarios
First: a Creative-mode Agent momentarily blunders, edits the shipped cordis/agent.cordis.yml directly and breaks it — what happens to the next session that wants Creative mode? Why does persona line 27 make “copy out and edit the copy” an iron rule? Second: when you assemble a fifth mode yourself, you leave same-named service-publishing lines that both presets want to publish in each file, neither wrapped in an isolate realm — what happens when two sessions mount at once? Hint: revisit how Minimal mode uses a realm to shadow fs.