Design: agent-compose - composed, cross-harness global agent context #134

Closed
opened 2026-06-03 21:39:47 +00:00 by coilysiren · 3 comments
Owner

agent-meld: composed, cross-harness global agent context

Summary

agent-meld composes a single global agent-context file (the meld) from
several org-level source files, scoped per machine, and wires it into all three
harnesses (Claude Code, Codex, OpenClaw) so each loads byte-identical context.
It is opt-in: hosts without a meld configured behave exactly as today.

This issue captures the v0 design for red-pen before any code lands.

Motivation

A machine often participates in more than one "org context" at once (public
conventions, a work context, one or more client contexts, a personal overlay).
We want each harness to load the right union of those contexts, the same way,
on every session, without:

  • duplicating large parent files into per-harness copies,
  • duplicating content within a single session, or
  • forcing any single repo to know about another (a public repo must not name a
    private one).

Background: how the three harnesses load context (verified)

  • Claude Code reads CLAUDE.md, not AGENTS.md. It walks up the directory
    tree concatenating CLAUDE.md / CLAUDE.local.md, and bridges to AGENTS.md
    via a one-line @AGENTS.md import. @path imports load in full at launch
    (max depth 4) and are not de-duplicated by resolved path - importing the
    same file twice includes it twice. User-global load point: ~/.claude/CLAUDE.md.
  • Codex reads AGENTS.md natively via a hierarchical directory cascade
    (deeper wins), capped by project_doc_max_bytes (32 KiB default). It does not
    lean on @-imports. AGENTS.override.md replaces the sibling AGENTS.md at
    its own level, but this is Codex-only. User-global load point: ~/.codex/AGENTS.md.
  • OpenClaw reads a single workspace AGENTS.md (symlinked to canonical) plus
    SOUL.md / USER.md. It floats over swappable models, often small local ones,
    so it has the tightest context budget of the three.

Key consequences:

  • @-import is Claude/Gemini-specific. The AGENTS.md standard's own import
    support is an open, unshipped issue (agentsmd/agents.md#11, #66). So we cannot
    rely on imports as the cross-harness composition mechanism.
  • No harness de-duplicates context for us. De-dup must be structural.
  • The one substrate all three honor is the filesystem: symlinks and the
    directory cascade.

Design

A generator builds one canonical composed file, e.g. ~/.config/agent-meld/meld.md:

  • the base source first (always),
  • then each in-scope delta, sorted alphanumerically by <org>/<repo> slug,
  • front matter stripped, with # --- BEGIN <slug> --- / END markers.

Each harness's global load point is then a symlink to that one file:

  • ~/.claude/AGENTS.md -> meld (and ~/.claude/CLAUDE.md stays the one-line
    @AGENTS.md bridge, since Claude reads CLAUDE.md),
  • ~/.codex/AGENTS.md -> meld,
  • OpenClaw workspace AGENTS.md -> meld.

One physical file, three symlinks, identical context everywhere. The base is
materialized once (into the meld), never per-harness, never copied at session time.

2. Scopes (per-machine, many-to-many)

A machine cannot be modeled by a single class (work / personal): contractors
have a many-to-many relationship between machines and jobs. So:

  • A machine declares a set of scope tags it participates in, in a small
    per-machine file (e.g. ~/.config/agent-meld/scopes), one tag per line.
  • Each org source declares which scope(s) it belongs to in front matter
    (scopes: [acme]), or always: true for the base.
  • The generator emits a source iff source.scopes ∩ host.scopes is non-empty,
    or it is always.

This makes machine-to-job many-to-many native: a client source is byte-identical
across machines and loads wherever that scope tag is present; a machine loads
whatever set of scopes it lists. The explicit per-machine file is also what
prevents accidental leaks - a freshly-cloned private repo is never composed in
unless its scope is listed.

3. always-global

Requirement: in-scope deltas load in every session on that machine, not only
when cwd is inside that org's tree. Because Codex and OpenClaw load a single
global file with no import expansion, "always-global with 2+ sources" forces a
concatenation. That is why the meld is one composed file (section 1) rather than
a pointer list.

4. Disjoint source convention (v0 de-dup against in-repo files)

Problem: if an org's always-global doctrine lived in that org's AGENTS.md, then
in a session where cwd is inside that tree, the harness would load the doctrine
twice - once from the meld, once from the cascade - and no harness de-dups.

Fix, by construction: the always-global doctrine lives in a filename the harness
cascade does not auto-load. Only the generator reads it.

<org>/<repo>/
  agent-meld.md   # always-global doctrine. ONLY the generator reads this ->
                  # goes into the meld. The cascade never loads it (wrong name).
  AGENTS.md       # repo-local only: how to work IN this repo. Cascade loads
                  # this in-tree. Contains no always-global doctrine.
  CLAUDE.md       # @AGENTS.md bridge, as normal.

The global content lives in exactly one harness-readable place (the meld) from
the start. There is no baseline to hide - no chmod, no override file, no
per-harness exclude. The two files are disjoint because the global content and
the repo-local content were never in the same file.

Alternatives considered and rejected for v0:

  • AGENTS.override.md empty stub - Codex-only, not cross-harness.
  • chmod / filesystem-permission hide - genuinely harness-agnostic and
    git-clean (git does not track the read bit), but correctness depends on every
    harness treating an unreadable file as "skip" not "error" (undocumented), it
    blinds the operator's own editor/grep, and read-bit denial is unreliable on
    Windows. Kept as a fallback, not the v0 default.

Tradeoff to accept: a stranger cloning a meld-participating repo and running a
plain harness without meld does not pick up the global doctrine (it is in
agent-meld.md, which their harness ignores). They still get the repo-local
AGENTS.md. This is acceptable - personal/org conventions are not something a
random cloner needs.

5. Scrub (allowlist, bridge-agnostic)

On every generate, sweep the harness global load points and skill mounts: remove
any symlink or pointer resolving into a repo not in the emitted (allowlisted)
set. A private/personal overlay is dropped because its scope is not listed on this
machine - never because anything names it. Scrub removes mounts only and warns
when an out-of-scope source repo is found on disk. It never deletes a checkout
unattended (that eats unpushed work).

6. Validators

We do not raise Codex's project_doc_max_bytes. Instead the meld stays small,
enforced by validators:

  • Size budget - the meld must fit the tightest in-scope consumer's
    budget. That is OpenClaw on a small local model, not Codex's 32 KiB. The cap
    is min over in-scope harnesses. The check fails setup.sh (and pre-commit
    where checkable) if exceeded.
  • Disjoint enforcement / drift - doctrine present in the meld must not also
    appear in a cascade-loaded AGENTS.md in the same repo. This is the dup check
    that keeps section 4 honest.
  • Generator drift - the committed/generated meld must match generator output,
    same pattern as the existing repo-pointer-skill generate + check pair.

7. Ordering

No priority field in v0 (premature). Order is derived:

  • always sources first (the base), as the lowest-priority layer,
  • everything else alphanumerically by <org>/<repo> slug,
  • later-emitted wins on conflict.

8. Heading-merge directives (v1, with a v0 trigger)

A future mechanism: sections carry a per-heading meld directive (overwrite vs
append), so a delta's restated section collapses against the base instead of
duplicating it. This both de-dups content and shrinks size.

This is v1 in general. It becomes v0-mandatory the moment a near-cap source
enters scope: the private personal overlay (agentic-os-kai) is already within
~10 chars of the cap on its own, so base + that overlay overflows immediately and
plain concat cannot fit. Rule: if a naive concat of in-scope sources exceeds the
budget, directives are required. A validator detects this and reports
"naive concat fits" vs "directives required."

Opt-in semantics

If no scopes file / meld config exists on a host, the generator does nothing:
no meld file, no symlink rewrites, no scrub. Harnesses load exactly as they do
today (in-repo AGENTS.md via cascade, whatever ~/.claude/CLAUDE.md already
points at). Activating the meld is the only thing that changes load behavior, and
deactivating restores the prior state.

Per-harness wiring

  • Claude - ~/.claude/CLAUDE.md = @AGENTS.md (one line); ~/.claude/AGENTS.md
    -> meld. Only per-harness file is the one-line bridge.
  • Codex - ~/.codex/AGENTS.md -> meld. No cap bump.
  • OpenClaw - workspace AGENTS.md -> meld. The constraining consumer for the
    size budget; it cannot be told to "load more," so the meld must be small.

Open questions / decisions for review

  • Exact paths for the meld file and the scopes file (~/.config/agent-meld/ vs
    ~/.claude/-adjacent).
  • Source filename convention: agent-meld.md vs *.meld.md vs a meld/ dir.
  • Front-matter schema: scopes: [...], always: true, room for future directives.
  • Whether to confirm OpenClaw's exact workspace AGENTS.md location during build.
  • Standalone repo: this is harness-agnostic and is effectively a userland
    implementation of the AGENTS.md import gap, so it likely earns its own
    MIT-licensed agent-meld repo/package, consumed by agentic-os's setup.sh
    (mirroring how the agentic_os package is pip-installed into many repos).
    Recommendation: build inside agentic-os first until the source convention and
    validators stop moving, then extract.

Out of scope (v0)

  • Heading-merge directives (v1, unless a near-cap source is in scope).
  • priority ordering field.
  • Raising Codex's project_doc_max_bytes.
  • Auto-deleting out-of-scope repo checkouts (scrub is mounts-only + warn).
# agent-meld: composed, cross-harness global agent context ## Summary `agent-meld` composes a single global agent-context file (the **meld**) from several org-level source files, scoped per machine, and wires it into all three harnesses (Claude Code, Codex, OpenClaw) so each loads byte-identical context. It is opt-in: hosts without a meld configured behave exactly as today. This issue captures the v0 design for red-pen before any code lands. ## Motivation A machine often participates in more than one "org context" at once (public conventions, a work context, one or more client contexts, a personal overlay). We want each harness to load the right union of those contexts, the same way, on every session, without: - duplicating large parent files into per-harness copies, - duplicating content within a single session, or - forcing any single repo to know about another (a public repo must not name a private one). ## Background: how the three harnesses load context (verified) - **Claude Code** reads `CLAUDE.md`, not `AGENTS.md`. It walks up the directory tree concatenating `CLAUDE.md` / `CLAUDE.local.md`, and bridges to `AGENTS.md` via a one-line `@AGENTS.md` import. `@path` imports load in full at launch (max depth 4) and are **not** de-duplicated by resolved path - importing the same file twice includes it twice. User-global load point: `~/.claude/CLAUDE.md`. - **Codex** reads `AGENTS.md` natively via a hierarchical directory cascade (deeper wins), capped by `project_doc_max_bytes` (32 KiB default). It does not lean on `@`-imports. `AGENTS.override.md` replaces the sibling `AGENTS.md` at its own level, but this is Codex-only. User-global load point: `~/.codex/AGENTS.md`. - **OpenClaw** reads a single workspace `AGENTS.md` (symlinked to canonical) plus `SOUL.md` / `USER.md`. It floats over swappable models, often small local ones, so it has the **tightest** context budget of the three. Key consequences: - `@`-import is Claude/Gemini-specific. The AGENTS.md standard's own import support is an open, unshipped issue (agentsmd/agents.md#11, #66). So we cannot rely on imports as the cross-harness composition mechanism. - No harness de-duplicates context for us. De-dup must be structural. - The one substrate all three honor is the filesystem: symlinks and the directory cascade. ## Design ### 1. One meld file, three symlinks A generator builds one canonical composed file, e.g. `~/.config/agent-meld/meld.md`: - the base source first (always), - then each in-scope delta, sorted alphanumerically by `<org>/<repo>` slug, - front matter stripped, with `# --- BEGIN <slug> ---` / `END` markers. Each harness's global load point is then a **symlink** to that one file: - `~/.claude/AGENTS.md` -> meld (and `~/.claude/CLAUDE.md` stays the one-line `@AGENTS.md` bridge, since Claude reads `CLAUDE.md`), - `~/.codex/AGENTS.md` -> meld, - OpenClaw workspace `AGENTS.md` -> meld. One physical file, three symlinks, identical context everywhere. The base is materialized once (into the meld), never per-harness, never copied at session time. ### 2. Scopes (per-machine, many-to-many) A machine cannot be modeled by a single class (`work` / `personal`): contractors have a many-to-many relationship between machines and jobs. So: - A machine declares a **set** of scope tags it participates in, in a small per-machine file (e.g. `~/.config/agent-meld/scopes`), one tag per line. - Each org source declares which scope(s) it belongs to in front matter (`scopes: [acme]`), or `always: true` for the base. - The generator emits a source iff `source.scopes ∩ host.scopes` is non-empty, or it is `always`. This makes machine-to-job many-to-many native: a client source is byte-identical across machines and loads wherever that scope tag is present; a machine loads whatever set of scopes it lists. The explicit per-machine file is also what prevents accidental leaks - a freshly-cloned private repo is never composed in unless its scope is listed. ### 3. always-global Requirement: in-scope deltas load in **every** session on that machine, not only when cwd is inside that org's tree. Because Codex and OpenClaw load a single global file with no import expansion, "always-global with 2+ sources" forces a concatenation. That is why the meld is one composed file (section 1) rather than a pointer list. ### 4. Disjoint source convention (v0 de-dup against in-repo files) Problem: if an org's always-global doctrine lived in that org's `AGENTS.md`, then in a session where cwd is inside that tree, the harness would load the doctrine **twice** - once from the meld, once from the cascade - and no harness de-dups. Fix, by construction: the always-global doctrine lives in a filename the harness cascade does **not** auto-load. Only the generator reads it. ``` <org>/<repo>/ agent-meld.md # always-global doctrine. ONLY the generator reads this -> # goes into the meld. The cascade never loads it (wrong name). AGENTS.md # repo-local only: how to work IN this repo. Cascade loads # this in-tree. Contains no always-global doctrine. CLAUDE.md # @AGENTS.md bridge, as normal. ``` The global content lives in exactly one harness-readable place (the meld) from the start. There is no baseline to hide - no chmod, no override file, no per-harness exclude. The two files are disjoint because the global content and the repo-local content were never in the same file. Alternatives considered and rejected for v0: - **`AGENTS.override.md` empty stub** - Codex-only, not cross-harness. - **chmod / filesystem-permission hide** - genuinely harness-agnostic and git-clean (git does not track the read bit), but correctness depends on every harness treating an unreadable file as "skip" not "error" (undocumented), it blinds the operator's own editor/grep, and read-bit denial is unreliable on Windows. Kept as a fallback, not the v0 default. Tradeoff to accept: a stranger cloning a meld-participating repo and running a plain harness without meld does not pick up the global doctrine (it is in `agent-meld.md`, which their harness ignores). They still get the repo-local `AGENTS.md`. This is acceptable - personal/org conventions are not something a random cloner needs. ### 5. Scrub (allowlist, bridge-agnostic) On every generate, sweep the harness global load points and skill mounts: remove any symlink or pointer resolving into a repo **not** in the emitted (allowlisted) set. A private/personal overlay is dropped because its scope is not listed on this machine - never because anything names it. Scrub removes **mounts only** and warns when an out-of-scope source repo is found on disk. It never deletes a checkout unattended (that eats unpushed work). ### 6. Validators We do not raise Codex's `project_doc_max_bytes`. Instead the meld stays small, enforced by validators: - **Size budget** - the meld must fit the **tightest in-scope consumer's** budget. That is OpenClaw on a small local model, not Codex's 32 KiB. The cap is `min` over in-scope harnesses. The check fails `setup.sh` (and pre-commit where checkable) if exceeded. - **Disjoint enforcement / drift** - doctrine present in the meld must not also appear in a cascade-loaded `AGENTS.md` in the same repo. This is the dup check that keeps section 4 honest. - **Generator drift** - the committed/generated meld must match generator output, same pattern as the existing repo-pointer-skill generate + check pair. ### 7. Ordering No `priority` field in v0 (premature). Order is derived: - `always` sources first (the base), as the lowest-priority layer, - everything else alphanumerically by `<org>/<repo>` slug, - later-emitted wins on conflict. ### 8. Heading-merge directives (v1, with a v0 trigger) A future mechanism: sections carry a per-heading **meld directive** (overwrite vs append), so a delta's restated section collapses against the base instead of duplicating it. This both de-dups content and shrinks size. This is v1 in general. It becomes **v0-mandatory** the moment a near-cap source enters scope: the private personal overlay (agentic-os-kai) is already within ~10 chars of the cap on its own, so base + that overlay overflows immediately and plain concat cannot fit. Rule: if a naive concat of in-scope sources exceeds the budget, directives are required. A validator detects this and reports "naive concat fits" vs "directives required." ## Opt-in semantics If no scopes file / meld config exists on a host, the generator does nothing: no meld file, no symlink rewrites, no scrub. Harnesses load exactly as they do today (in-repo `AGENTS.md` via cascade, whatever `~/.claude/CLAUDE.md` already points at). Activating the meld is the only thing that changes load behavior, and deactivating restores the prior state. ## Per-harness wiring - **Claude** - `~/.claude/CLAUDE.md` = `@AGENTS.md` (one line); `~/.claude/AGENTS.md` -> meld. Only per-harness file is the one-line bridge. - **Codex** - `~/.codex/AGENTS.md` -> meld. No cap bump. - **OpenClaw** - workspace `AGENTS.md` -> meld. The constraining consumer for the size budget; it cannot be told to "load more," so the meld must be small. ## Open questions / decisions for review - Exact paths for the meld file and the scopes file (`~/.config/agent-meld/` vs `~/.claude/`-adjacent). - Source filename convention: `agent-meld.md` vs `*.meld.md` vs a `meld/` dir. - Front-matter schema: `scopes: [...]`, `always: true`, room for future directives. - Whether to confirm OpenClaw's exact workspace AGENTS.md location during build. - Standalone repo: this is harness-agnostic and is effectively a userland implementation of the AGENTS.md import gap, so it likely earns its own MIT-licensed `agent-meld` repo/package, consumed by `agentic-os`'s `setup.sh` (mirroring how the `agentic_os` package is pip-installed into many repos). Recommendation: build inside `agentic-os` first until the source convention and validators stop moving, then extract. ## Out of scope (v0) - Heading-merge directives (v1, unless a near-cap source is in scope). - `priority` ordering field. - Raising Codex's `project_doc_max_bytes`. - Auto-deleting out-of-scope repo checkouts (scrub is mounts-only + warn).
Author
Owner

path should be ~/.config/agent-meld/

source should be AGENTS.MELDED.md

path should be `~/.config/agent-meld/` source should be AGENTS.MELDED.md
Author
Owner

🤖 Filed by Claude Code on Kai's behalf.

Feature compatibility matrix - the real-world cases agent-meld must satisfy, and the canonical test cases for the scope-based-inclusion slice.

  • scopes - kai-public (always-global doctrine, on every machine), work, kai-private, eco
  • work mac - scopes {work, kai-public}
  • personal mac - scopes {kai-public, kai-private}
  • personal windows (Eco modding box) - scopes {kai-public, eco}

kai-public is the only scope shared by all three, so it is the always-global rung. Each machine carries exactly one context-specific scope on top of it. Any scope-inclusion implementation must reproduce this 3x4 matrix exactly.

🤖 Filed by Claude Code on Kai's behalf.

> 🤖 Filed by Claude Code on Kai's behalf. **Feature compatibility matrix** - the real-world cases agent-meld must satisfy, and the canonical test cases for the scope-based-inclusion slice. - **scopes** - `kai-public` (always-global doctrine, on every machine), `work`, `kai-private`, `eco` - **work mac** - scopes `{work, kai-public}` - **personal mac** - scopes `{kai-public, kai-private}` - **personal windows** (Eco modding box) - scopes `{kai-public, eco}` `kai-public` is the only scope shared by all three, so it is the always-global rung. Each machine carries exactly one context-specific scope on top of it. Any scope-inclusion implementation must reproduce this 3x4 matrix exactly. > 🤖 Filed by Claude Code on Kai's behalf.
coilysiren changed title from Design: agent-meld - composed, cross-harness global agent context to Design: agent-compose - composed, cross-harness global agent context 2026-06-03 23:25:48 +00:00
Author
Owner

🤖 Filed by Claude Code on Kai's behalf.

Epic complete. agent-compose (composer + AGENTS.COMPOSE.md discovery + scope-based inclusion + size/dedup/drift validators) is live on origin/main at 819b09c. All six slices shipped and closed:

  • #135 spine (opt-in composer + harness symlinks)
  • #136 source discovery via AGENTS.COMPOSE.md
  • #137 scope-based inclusion (3-machine compat matrix)
  • #138 size-budget validator
  • #139 dedup validator
  • #140 composer drift detection

143 tests green. Closing the design tracker.

🤖 Filed by Claude Code on Kai's behalf.

> 🤖 Filed by Claude Code on Kai's behalf. Epic complete. agent-compose (composer + AGENTS.COMPOSE.md discovery + scope-based inclusion + size/dedup/drift validators) is live on origin/main at 819b09c. All six slices shipped and closed: - #135 spine (opt-in composer + harness symlinks) - #136 source discovery via AGENTS.COMPOSE.md - #137 scope-based inclusion (3-machine compat matrix) - #138 size-budget validator - #139 dedup validator - #140 composer drift detection 143 tests green. Closing the design tracker. > 🤖 Filed by Claude Code on Kai's behalf.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os#134
No description provided.