-
Notifications
You must be signed in to change notification settings - Fork 0
cross harness identity and rules
Status: design spec — not yet implemented. The 6 phases below are tracked as bd issues
(main-3va flat-file rules fix, main-ylz stack-level instructions:, main-72j antigravity,
main-7rh codex, main-rlw opencode, main-w8k omp) — this doc lives in docs/research/ as the
implementation reference until the last phase ships, then the governing-principle section and
harness-comparison table below should move to docs/harnessed-design.md.
Date: 2026-07-02 (governing principle + omp correction added 2026-07-03)
Companions: harness-rules-directory-support.md
(per-harness native .agents/rules/-equivalent research), docs/guides/recipe-authoring.md (the
rules: field), src/harnessed/synclinks.py (current fan-out mechanism),
home-folder-codex-requirements.md and
home-folder-opencode-requirements.md (2026-07-03
— the history-surfacing research this spec's "don't confuse config with storage" principle depends
on for two more harnesses).
Containerize the configuration, not the storage. Conversations, usage, and stats must persist
and stay coherent regardless of which harnessed stack (tool configuration) launched a given
session — the same underlying identity/history for a harness should be usable across multiple
different stacks (e.g. claude_dev-core and claude_dev-methodology both writing into the same
host Claude history, because the mount is keyed by project path, not by stack name). This is also
the foundation for team-deployable configurations: a stack (recipes + rules + the instructions:
field this spec adds) is the shareable, version-controlled unit; auth and history stay strictly
personal and host-linked, never baked into shared config.
This reframes one earlier conclusion in this spec: omp's full ~/.omp/agent rw-mount (see below)
is not a risk to trim — it's the target pattern, because it's what guarantees continuity across
every omp-harness stack and native host omp. See ROADMAP.md D3 (now closed, confirmed correct)
and docs/research/home-folder-omp-requirements.md (updated 2026-07-03 to reconcile its original,
now-superseded recommendation against this).
Concrete landmine to guard against: Stack.state.session_state already supports volume as an
alternative to the default host (see docs/guides/stacks.md) — that isolates session state
per-stack instead of sharing the host store, the exact opposite of this principle. A team-shared
stack that sets this (even accidentally) would silently fragment everyone's history per-stack.
Worth a loud warning wherever session_state is documented, and possibly worth requiring an
explicit, harder-to-stumble-into opt-in for volume rather than a same-looking sibling of host.
Two genuinely different concerns were getting conflated in earlier discussion:
-
Stack-level identity — "what is this assembled agent, as a whole." One per stack, authored
once by the stack author. This is CLAUDE.md's role for
claude, and the closest thing to a system prompt override for the others. -
Recipe-level rules — topic-scoped, composable, N-per-stack, already shipped as the
rules:recipe field (T10). Abeadsrecipe ships a rule aboutbdusage; asuperpowersrecipe ships one about its workflow; they compose without collision (synclinks.pyfail-fast on name clash).
Trying to solve both with one mechanism is what caused the earlier confusion (e.g. "just append to CLAUDE.md" breaks down the moment two recipes want to append). They need separate schema fields and separate build-time handling.
Also: T10's rules: fan-out has a real bug, independent of everything below. Official Claude
Code docs confirm rules are flat .md files (.claude/rules/<name>.md, or nested for topic
organization — .claude/rules/frontend/react.md — but never a directory-per-rule). synclinks.py
_register() currently requires src.is_dir() and does shutil.copytree — the skills: pattern,
copy-pasted for rules: without checking the shape. Skills genuinely need directories (SKILL.md +
resources); rules don't. Fix this regardless of the design below — it's a small, isolated
correction (FileExt needs a file-vs-dir mode, or a new leaner RuleExt).
| Tier | Owner | Cardinality | Claude Code analog |
|---|---|---|---|
| Identity |
Stack (new field, e.g. instructions:) |
One per stack | .claude/CLAUDE.md |
| Rules |
Recipe (existing rules: field, T10) |
N per stack, composed | .claude/rules/<name>.md |
Identity is authored once, by whoever builds the stack. Rules are contributed by whichever recipes
are in the stack's recipes: list. Both need deriving into whatever the target harness natively
understands.
Not every harness has a literal "modify the system prompt" primitive. Where one exists, prefer it (more direct, doesn't compete with the harness's own default instructions-file semantics). Where it doesn't, fall back to appending into that harness's instructions-file.
| Harness | System-prompt hook? | Target | Baked or host-mounted? | Merge complexity |
|---|---|---|---|---|
| claude | No separate hook — CLAUDE.md is the only surface | .claude/CLAUDE.md |
Profile-baked ($XDG_DATA_HOME/.../profiles/<stack>/.claude/) |
New file, no existing content to merge with |
| omp |
~/.omp/agent/APPEND_SYSTEM.md exists as a mechanism, but no viable write path — see below |
AGENTS.md-equivalent fallback only, for now |
Host-shared (~/.omp/agent is rw-mounted from the real host dir, per _omp_agent_mount — same dir used by every omp stack AND native host omp) |
Blocked — see resolution below |
| codex |
model_instructions_file = "..." exists, but it replaces Codex's built-in instructions entirely (confirmed: "the heavier hammer... replaces built-in instructions"), same category as omp's SYSTEM.md — not an addition. Given the append-first principle, this is not the default target. |
Default to AGENTS.md (append/context-style, global ~/.codex/AGENTS.md); leave model_instructions_file as an opt-in escape hatch for a stack that explicitly wants full override |
Image-baked, profile-scoped (Dockerfile.harnessed-codex already writes ~/.codex/config.toml with [mcp_servers.hatago]) |
AGENTS.md is a fresh file, no merge. model_instructions_file (if ever used) needs a TOML merge into the existing baked config.toml. |
| opencode | Define a custom agent in opencode.json ("prompt": "{file:./prompts/my-persona.md}") and invoke with opencode --agent <name> — confirmed safe: agent-level permissions inherit from global config unless explicitly overridden (most default to "allow"), so an agent defined with only a custom prompt behaves identically to default otherwise. |
Custom agent + changed attach command |
Image-baked (Dockerfile.harnessed-opencode already writes ~/.config/opencode/opencode.json with the hatago MCP entry) |
JSON merge required (simpler than TOML) + _HARNESS_ATTACH_CMD["opencode"] needs to become stack-conditional, not a fixed per-harness string as it is today |
| antigravity |
gemini.md (project root, auto-loaded) or ~/.gemini/antigravity-cli/settings.json's context.fileName: [...] to point at a global file — confirmed safe to bake: settings.json is explicitly marked "Surface? No" in home-folder-antigravity-requirements.md (this repo) — never host-mounted, unlike the conversation/history dirs it sits alongside. |
Bake settings.json + the referenced .md, same pattern as the already-baked mcp_config.json
|
Image-baked, profile-scoped — no conflict (resolved; see below) | New files, no existing content to merge with |
I downloaded @drmikecrowe/omp-claude-hooks-bridge@0.2.2 from npm and read index.ts directly (not
just its README). It is purely a hook-execution bridge — it maps Claude Code's
SessionStart/UserPromptSubmit/PreToolUse/PostToolUse/Stop hooks onto omp's extension
lifecycle events (session_start, before_agent_start, tool_call, tool_result, agent_end)
and runs the configured shell commands. Checked the session_start handler specifically
(notifySessionStartHookResult, index.ts:899) — it only posts a UI notification
(ctx.ui.notify(...)). It never reads hookSpecificOutput.additionalContext and has no
content-injection capability at all. The earlier assumption that this bridge was "already the
integration point for Claude-canonical content reaching omp" was wrong — it bridges hook
execution, not instructions/context.
Real options for omp, neither clean:
-
Guarded, idempotent append into the shared
~/.omp/agent/APPEND_SYSTEM.md/RULES.md— delimited markers (<!-- harnessed:stack:<name> -->...<!-- /harnessed -->), same pattern as the existing CLAUDE.md nudge trick in theSuperpowers/hyperpowersPLAN.md docs. Ships now; accepts that multiple omp-harness stacks share one file (their content coexists via markers, not a true per-stack profile-scoped file). -
Contribute real injection support to
omp-claude-hooks-bridgeitself (e.g. handleadditionalContextfrom a SessionStart hook the way Claude Code's own SessionStart mechanism does, then havesession_start's handler feed it into omp's context) — clean, profile-scoped, but real new development in an external repo (yours), not part of this implementation.
Decision needed: ship (1) now and treat (2) as a future upstream contribution, or block omp entirely on (2)? Not yet decided.
Once the T10 flat-file bug is fixed, .claude/rules/*.md (recipe-contributed, composed per stack)
is the canonical source. Harnesses that read it directly (claude; antigravity via .agents/rules/,
same flat-file shape) need no extra work beyond mirroring. Harnesses with no directory-based rules
concept need a derived, concatenated single file built at assemble time:
-
codex: no directory-rules primitive at all — concatenate into
AGENTS.md(same file as the identity fallback target above; mind the 32 KiBproject_doc_max_bytescap when both share one file — identity content plus every rule could hit it sooner than either alone). -
omp:
RULES.mdis the native analog (global + project both apply, unlikeSYSTEM.md's nearest-wins) — same host-shared-write problem as identity above, same two options (guarded append now, or real bridge injection later). -
opencode: has native glob support in
instructions:(itsopencode.jsoninstructions:array), so it may not need concatenation at all — point it at.claude/rules/*.mddirectly using an absolute container path (/home/harnessed/.claude/rules/*.md), not a bare relative path — all of opencode's own doc examples resolve paths project-relative, and the profile lives under container$HOME, not the mounted project.
paths:-conditional semantics — decided, not just a leaning. Claude Code rules can carry
paths: frontmatter for conditional loading (only active when a matching file enters context).
Decision: don't support this outside Claude. Every other harness concatenates everything and
loads it always-on. This is an accepted, permanent limitation, not a gap to close later — Claude
gets true conditional rule loading; every other harness gets "all rules, all the time."
All four original open questions are now resolved:
-
Antigravity
settings.jsonvs. host-mounted history dir — no conflict. Re-readhome-folder-antigravity-requirements.md's own disposition table:settings.jsonis explicitly marked "Surface? No" — never host-mounted, same treatment as the already-bakedmcp_config.json. Safe to bake identity config there. -
omp-claude-hooks-bridgehook API — no injection surface exists. Confirmed by reading the actual package source (not just its README): it's a hook-execution bridge only, noadditionalContexthandling anywhere. See the omp section above for the resulting two options (guarded shared-file append now, or real bridge development later) — still an open decision, not a technical unknown anymore. -
opencode --agent <name>side effects — confirmed safe. Agent permissions inherit from global config unless explicitly overridden; a custom agent with only apromptfield behaves identically to default otherwise. -
Rules concatenation semantics — decided, not just resolved: no
paths:-conditional support outside Claude, ever. Concatenate everything for every other harness.
omp decision (2026-07-02): ship via guarded shared-file append. Write into
~/.omp/agent/{APPEND_SYSTEM,RULES}.md with idempotent, delimiter-marked blocks per stack (same
pattern as the existing CLAUDE.md nudge trick). Works today; shared across all omp usage on the
host, not profile-scoped — an accepted, documented tradeoff, not a blocker. Real injection support
in omp-claude-hooks-bridge stays a future upstream improvement, not a prerequisite.
-
T-rules-fix: fix the flat-file bug in
synclinks.py/schema.pyforrules:— small, isolated, no design dependencies. Do this regardless of the rest. -
Stack-level
instructions:field (schema + assemble →.claude/CLAUDE.md) — claude only, no cross-harness complexity, proves the two-tier model end-to-end. -
antigravity (bake
settings.json+ identity.md, same pattern as the existingmcp_config.jsonbake) — no longer blocked, genuinely simple now. -
codex (write
~/.codex/AGENTS.md, no merge needed since it's a fresh file, notmodel_instructions_file) — self-contained, no host-mount risk. -
opencode (JSON merge into the existing baked
opencode.json+ conditional attach command) — more launcher surface area than codex/antigravity. - omp — needs the guarded-append-vs-bridge-development decision above before starting.
-
docs/research/harness-rules-directory-support.md— the per-harness native rules-directory research this spec builds on. -
docs/research/home-folder-antigravity-requirements.md— the antigravity host-mount design this spec's open question 1 depends on. -
src/harnessed/synclinks.py— current (buggy, forrules:) fan-out mechanism. -
catalog/agents/{omp,codex,opencode,antigravity}/agent.yaml,catalog/base/Dockerfile.harnessed-*— the per-harness images this spec's baked-config changes would touch.
Start Here
Guides
- Recipe authoring
- Service authoring
- Stacks
- Extending stacks (proposed)
- Recipe catalog
- System prompt & rules (proposed)
- Secrets
- AWS SSO
- Pulumi (host login forwarding)
- Egress & exposing services
- Container filesystem
- Git hooks
- Troubleshooting
- Pin management (harnessed update)
Codebase Map
Planning & Roadmap
- open work: GitHub Issues
Research & Prompts
- research/ (home-folder requirements per harness, browse in-repo)
- prompts/ (reusable prompt templates, browse in-repo)