One-file Extensions
CortexFS follows the same anti-framework extension rule as Pi: add behavior at stable edges (packages, executables, skills, modules, channel adapters) without a second root ABI or a resident plugin daemon. Product placement of those edges is in architecture.md (Extension points). This page is the shortest authoring path for existing compatibility surfaces.
The shortest way to add behavior is one package directory. Keep the program
logic in normal executables; keep the wiring in one cortexfs.toml:
review-kit/
├── cortexfs.toml
└── bin/
├── review-agent
└── git-summary
schema = "cortexfs.package/v1"
name = "review-kit"
version = "0.1.0"
[[tools]]
name = "git.summary"
run = "bin/git-summary"
description = "Summarize the current Git worktree"
schema = { type = "object" }
[[agents]]
name = "kit_reviewer"
run = "bin/review-agent"
abi = "sdk-envelope-v1"
model = "main"
tools = ["git.summary"]
instructions = "Review changes, use the tool when useful, and cite evidence."
parent = "agent:architect"
The executable Agent SDK example above is a compatibility surface from the
former self-hosted runtime. New hosted CLI integrations should prefer a thin
process launch profile instead of adding new loop/provider/session behavior to
sdk-envelope-v1.
Validate the complete package without writing a backing tree, then install it:
ctx install --check ./review-kit
ctx install ./review-kit
For a prebuilt package, bind each member to its distributed bytes by adding the
exact lowercase digest next to run, then require every member to have one:
[[tools]]
name = "git.summary"
run = "bin/git-summary"
sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
ctx install --check --require-hashes ./review-kit
Replace the example digest with the output of sha256sum. Every declared
sha256 is checked, even without --require-hashes; the flag additionally
rejects a package when any tool or agent omits its digest.
ctx install --check finds cortexfs.toml, hashes every executable, renders
and checks every strict object manifest, then exits before choosing or writing
a backing tree. Normal ctx install repeats those checks before publishing
each object through the existing atomic object installer. A matching digest
binds the descriptor to the executable bytes, but does not authenticate a
publisher or registry. Obtain the descriptor and expected digest through an
authenticated trusted channel; cortexfs.package/v1 does not define signatures.
Use --source PATH when the mounted tree is backed by a specific generation,
and use --tier user for tools that should only be visible to the current user.
Agent objects are system-tier because their runtime socket is host-owned:
ctx install ./review-kit --source /var/lib/cortexfs/storage/current
Agent Unix identity is host authority, not package metadata. The installer derives it from its effective user and supplementary groups; package authors cannot select a uid, gid, or privileged group.
The run file is the extension point. A tool implements the Tool SDK and a
legacy executable agent implements the Agent SDK; both are ordinary executable
files, so a Rust, shell, or another host-language build can produce them. An SDK
agent receives one hosted envelope on stdin and returns JSONL events. It may
yield a tool call; the host performs the capability check and sends the
observation back for the next step. This is compatibility behavior, not the
target architecture for new Agent CLI integrations.
For a build-free compatibility agent, copy
examples/extensions/shell-agent/. It uses POSIX shell plus jq, requires the
seven core keys, permits the SDK-optional event/origin keys, rejects every
unknown envelope key, preserves the runtime's forward-compatible origin
extension behavior, enforces byte bounds, validates known present event/origin
values, caps each response at the runtime's 256 KiB newline-inclusive limit,
and rejects a wrong launch marker, sticky frames, mismatched run/step values,
and continuations it does not implement. It then emits one canonical assistant
message frame:
CTX_BIN=ctx ./examples/extensions/shell-agent/install.sh
CORTEXFS_EXTENSION_INSTALL=yes \
CTX_SOURCE=/var/lib/cortexfs/storage/current \
./examples/extensions/shell-agent/install.sh
ctx agent start field-notes --session demo --cwd /workspace
ctx agent send field-notes --session demo "record this decision"
The first command only validates. Installation remains an explicit second
step. Run scripts/shell-agent-smoke.sh for the provider-free envelope test.
Use cortexfs-agent-sdk only for existing compatibility consumers; do not grow
new provider/model/session orchestration there when a hosted CLI already owns
that behavior.
Official compatibility defaults remain overrideable:
loop=chat|react|coding|planner|research built-in behavior hint (default chat)
loop=<name> + loop.d/<name> custom loop driver executable
compact.strategy=truncate|summarize|<name> history rebuild strategy (default truncate)
compact.d/<name> custom compaction executable
invoke.strategy=default|cli|sdk|<name> tool invoke surface (default default)
invoke.d/<name> custom tool invoke executable
adapter=<family>|<name> channel adapter family or custom name
adapter.d/<name> custom channel socket driver executable
Agent SDK BuiltinLoop helpers interpret CTX_AGENT_LOOP inside your binary
Tool SDK InvokeMode helpers read CTX_TOOL_MODE / CTX_AUTHORIZED_OBJECT
Channel SDK DriverLaunchConfig read CORTEXFS_CHANNEL_* / CTX_CHANNEL_* env
Do not add new Agent-loop features to these compatibility controls during the hosted-CLI migration.
Topology is just the parent edge. Every agent names its parent as
agent:NAME (optional session: and run: qualifiers remain available), so a
tree is visible in the same control files that enforce ownership:
[[agents]]
name = "planner"
run = "bin/planner"
parent = "agent:architect"
[[agents]]
name = "builder"
run = "bin/builder"
parent = "agent:planner"
The package file is authoring input, not a second /ctx namespace. After
installation the durable result is still only agent/<name>.d/*,
tool/<name>.d/*, ordinary session files, and the existing sockets. The raw
ctx object install command remains available for package builders that need
full manifest control; most users do not need to see it.
Development/config activation is commit-bound. Commit the package or
configuration first; a later process restart is ordinary lifecycle that may
consume the already committed generation. Restart must never make uncommitted
package/config changes authoritative. ctx install never starts a watcher,
polling loop, or background plugin service.