Shared vs cited modules
Status (culture 11.0.0, 2026-05-11): This rule is now historical for culture’s own tree. The agent harness moved to the sibling cultureagent package in Phase 1 of the extraction; culture’s culture/clients/<backend>/{config,constants}.py and culture/clients/shared/*.py are re-export shims forwarding to cultureagent.clients.<backend>.* / cultureagent.clients.shared.*, and packages/agent-harness/ has been deleted. The two-tier model below still applies inside cultureagent (where the backends actually live). Culture’s own code no longer hosts cited modules; new backend-specific features should be proposed upstream against cultureagent’s repo.
The culture agent harness uses a two-tier code-distribution model.
The rule
A harness module belongs in culture/clients/shared/ if it has no backend-specific behavior — nothing in it would ever differ between claude, codex, copilot, or acp. Pure logic and pure-glue I/O qualify; orchestration that reads SDK-specific shapes does not.
Cited modules live in packages/agent-harness/ and are copied byte-for-byte into each backend at culture/clients/<backend>/. The all-backends rule — “a feature in only one backend is a bug” — applies to the cited tier.
Shared modules live in culture/clients/shared/ and are imported directly by every backend. The all-backends rule doesn’t need to apply because Python’s import system enforces it.
Current file list
Shared (imported)
| File | Why shared |
|---|---|
attention.py | Pure state machine; no I/O, no SDK shapes |
message_buffer.py | Pure value type |
ipc.py | Frame encoder/decoder for whisper protocol |
telemetry.py | OTel glue; identical config across backends |
irc_transport.py | RFC 2812 client wrapper; no SDK shapes |
socket_server.py | Unix-socket whisper plumbing |
webhook.py | urllib.request POST; identical schema |
webhook_types.py | WebhookConfig dataclass |
Cited (copied)
| File | Why cited |
|---|---|
daemon.py | Each backend’s main loop wraps SDK-specific shapes (claude-agent-sdk, codex-agent-sdk, etc.) |
config.py | Per-backend defaults and SDK-specific options |
constants.py | Per-backend literals (channel names, timeouts) |
agent_runner.py | “Yours to write” — the SDK call site itself |
supervisor.py | “Yours to write” — backend-specific liveness logic |
The cited tier’s parity is locked down by tests/harness/test_all_backends_parity.py; the shared tier’s “no per-backend copy leaked” property is locked down by tests/harness/test_no_per_backend_copy_of_shared_modules.py.
Fork-back procedure
If a shared module needs to start diverging for one backend (for example, an SDK upgrade forces telemetry to emit different attributes per backend):
cp culture/clients/shared/X.py culture/clients/<backend>/X.pyfor each backend that needs the local copy.- In that backend’s code (its
daemon.pyand any tests that targeted the shared path), changefrom culture.clients.shared.X import …tofrom culture.clients.<backend>.X import …. - Leave any backends that still agree pointing at
shared/. - Re-add
X.pyto the parity matrix intests/harness/test_all_backends_parity.pyfor the now-cited backends so the cite-paste invariant is enforced again for them. - Move
Xfrom the “Shared” table above to the “Cited” table in this doc, and update the Shared vs cited paragraph inCLAUDE.mdto match.
The two-tier model bends without breaking. The shared tier is not an all-or-nothing commitment — it just describes where the line currently is.