architecture(agent): establish a Free4Chat-owned Harness semantic compatibility layer
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 1.2k
- Forks
- 166
- Avg merge
- 1h 5m
- Merged PRs (30d)
- 246
Description
Why this exists
Recent Remote Task dogfood exposed a repeated integration risk:
Free4Chat currently relies on multiple Harness/ACP implementations with materially different semantics:
- Hermes — native ACP
- OpenCode — native ACP
- Codex —
@agentclientprotocol/codex-acp - Claude —
@agentclientprotocol/claude-agent-acp - Pi —
pi-acp - future built-ins may add more implementations
ACP is a useful transport/protocol boundary, but ACP support alone is not a sufficient product contract for Free4Chat.
Two concrete production-grade examples now prove that:
Pi session lifecycle
Free4Chat needs:
load another retained session
→ must not destroy an unrelated active Task
But pi-acp@0.0.33 uses closeAllExcept() from session/new / session/load, which can kill another active per-session Pi worker and leave its session/prompt unresolved.
The Free4Chat Runtime/lane design was not the root cause. A production-shaped probe against upstream PR svkozak/pi-acp#131 verified that preserving concurrent session workers restores the desired behavior:
load A
→ prompt A active
→ load B
→ A continues
→ A/B make real concurrent progress
Track the user-facing Task consequence in #421.
Codex approval behavior
Free4Chat needs:
provider requests an exact local approval
→ Free4Chat can present it remotely
→ exact decision returns to the same turn
But compatibility depends on both Codex app-server behavior and the exact codex-acp version/policy. #297's historical result was based on an older bridge; current re-verification is tracked in #426.
These are not isolated bugs. They demonstrate a repeated boundary problem:
Runtime code should depend on Free4Chat-owned semantics, not on assumptions about how a particular ACP implementation interprets the protocol.
Refs #297, #409, #421, #426.
Architectural principle
Do not replace ACP.
Instead:
Free4Chat Runtime
↓
Free4Chat Harness semantic contract
↓
provider-specific compatibility adapter
↓
ACP transport / native Harness protocol / bridge
↓
Harness
ACP remains the primary transport where appropriate.
Free4Chat owns the product-level semantics above it.
The compatibility layer absorbs:
- provider/bridge quirks;
- version-specific workarounds;
- capability normalization;
- safe fallbacks;
- upstream compatibility fixes;
- exact evidence about what a Harness really supports.
The Runtime should not accumulate:
if pi { ... }
if codex { ... }
if claude { ... }
for provider-specific behavior.
Product contract to own
Only add semantics that are already earned by real product requirements.
Session
discover/list
load/resume exact native conversation
stable native session identity
safe materialization
no silent fresh-session fallback
typed session loss/failure
Important invariant:
Session materialization must never destroy an unrelated active turn.
Turn execution
run long-lived turn
same-session serialization
bounded cross-session concurrency where verified
exact-turn cancel
stream/activity routing isolation
failure isolation where provider permits
Approval
Represent provider truth explicitly.
Examples:
unsupported
native-policy/no-prompt
room-mediated
partial/upstream-limited
Do not reduce this to one optimistic boolean.
Lifecycle
process/session materialization
re-materialization
bridge reconnect
provider child death
cleanup
session lost
Artifacts / Task scope
Keep exact Task correlation and no ambiguous "current Task" guessing under concurrency.
Target internal shape
Exact names are implementation decisions, but the ownership should converge toward something like:
agent/internal/harness/
contract.go
capabilities.go
acp/
transport.go
protocol.go
providers/
pi/
codex/
claude/
opencode/
hermes/
Conceptually:
type HarnessDriver interface {
Capabilities() Capabilities
Sessions() SessionDriver
Turns() TurnDriver
}
The important part is not the exact interface shape. The important part is:
Runtime calls one Free4Chat semantic seam; provider-specific quirks stay behind that seam.
Do not create a second go.mod or a new repository yet.
Keep this internal to the Agent repo until there is evidence that another consumer needs an independent module.
Capability policy
Separate three concepts:
protocol/adaptor advertises X
≠
Free4Chat source code appears to support X
≠
Free4Chat product capability VERIFIED
A built-in capability is enabled only after a real conformance probe.
Examples:
SessionContinuation:
unsupported | source-supported | verified
Execution:
serial | cross-session
maxConcurrent
verification status
Approval:
unsupported | native-policy | room-mediated | partial
Do not infer product support only from ACP advertised capabilities.
Harness certification / conformance suite
The repeated manual probes from #297 / #409 / #421 should become reusable engineering assets.
Target a provider-neutral certification surface, eventually callable conceptually as:
free4chat-agent harness probe pi
free4chat-agent harness probe codex
A probe report may include:
session discovery PASS
existing-session continuation PASS
safe materialization PASS
long-running turn PASS
same-session serialization PASS
cross-session concurrency VERIFIED / SERIAL / UNVERIFIED
exact cancel PASS
stream routing isolation PASS
permission mediation ROOM / NATIVE / PARTIAL / UNSUPPORTED
process failure isolation PASS / provider-global
Do not make all probes mandatory for every Harness.
A Harness may remain useful with a smaller verified capability set.
Dependency ownership policy
Do not respond to upstream bugs by automatically rewriting every bridge.
Use this hierarchy:
1. Native / healthy upstream
pin exact version
→ run Free4Chat certification
→ use directly
2. Upstream bug with a narrow fix
reproduce
→ submit/support upstream issue/PR
→ keep compatibility shim if required
3. Product-critical upstream bug + no timely usable release
Free4Chat may own distribution temporarily:
minimal i365dev fork
+ immutable pin
+ upstream-aligned patch only
+ explicit removal condition
The goal is own the product semantics and distribution escape hatch, not to maintain unrelated upstream features forever.
4. Upstream fix lands
Delete the workaround/fork path where possible and return to the simpler upstream implementation.
Compatibility code should be removable.
Provider-specific "dirty work" belongs here
Examples:
Pi
If upstream still needs compatibility handling:
Pi provider adapter
→ normalize safe session materialization
→ preserve active conversations
Runtime must not know about closeAllExcept().
Current upstream candidate:
https://github.com/svkozak/pi-acp/pull/131
Codex
The Codex provider adapter may normalize:
- bridge version selection;
- mode/config behavior;
- approval capability classification;
- app-server/bridge limitations;
- version-specific compatibility behavior.
Current re-verification:
#426
Runtime should only consume the Free4Chat approval/session semantics.
Non-goals
This issue is NOT permission to:
- rewrite all Harness bridges;
- invent a new wire protocol to replace ACP;
- build a universal Agent framework;
- create a generic plugin marketplace;
- split Harness code into a separate repository/module immediately;
- add speculative abstractions for future providers;
- rewrite ResidentRuntime;
- move provider policy into Room/Worker code;
- enable unverified concurrency/continuation/approval capabilities;
- fork upstream projects without a concrete product-critical reason.
This refactor must be earned and incremental.
Refactor strategy
Do not stop current product stabilization for a broad architecture rewrite.
Preferred sequencing:
Phase 1 — establish the seam
Extract the smallest Free4Chat-owned semantic interface around the behavior Runtime already depends on.
Move existing provider selection/capability policy behind it.
Old behavior must remain byte-for-byte or observably equivalent.
Phase 2 — move earned quirks behind provider adapters
Start with the currently proven cases:
- Pi session materialization / concurrency compatibility;
- Codex version/policy/approval compatibility as #426 determines.
Do not manufacture quirks for providers that do not need them.
Phase 3 — conformance tests
Turn existing real probe invariants into deterministic provider-neutral tests where possible.
Keep real-provider probes separate from unit tests.
Phase 4 — future Harness onboarding
A new built-in Harness should implement the semantic seam and gain capabilities only after verification.
Structural quality bar
Target:
minimum necessary structural change + clear ownership + testable boundary + lower future maintenance entropy
Reject:
- ResidentRuntime becoming a provider switchboard;
- provider conditionals scattered through Runtime;
- one abstraction hierarchy per Harness;
- duplicate Task/session state machines;
- compatibility code mixed into Room protocol handlers;
- generic framework code with no current consumer.
An earned narrow provider seam is the goal.
Acceptance
This architecture issue is complete when:
- Runtime depends on a provider-neutral Free4Chat Harness semantic seam for the current session/turn operations;
- provider-specific compatibility logic is no longer spread through Runtime;
- existing Pi/Codex policies are represented centrally and truthfully;
- Pi lifecycle quirks can be handled/replaced without changing Runtime semantics;
- Codex approval/version behavior can be changed/re-verified without changing generic approval core;
- deterministic tests protect the Free4Chat semantic invariants;
- a minimal Harness certification/probe shape is documented or implemented;
- all existing built-in Harnesses retain their current verified capability level unless fresh evidence upgrades them;
- no independent module/repository is created without a real second consumer;
- no product capability is enabled solely because ACP advertises it.
Current sequencing
Do not block the active v0.5.35 production-dogfood stabilization work.
In parallel:
current Task stabilization
→ fix production UX/correctness
this issue
→ narrow semantic seam refactor
Pi upstream #131
→ track / validate
Codex #426
→ re-verify current bridge behavior
Prefer one focused architecture PR for the initial seam rather than many tiny PRs, but do not combine unrelated mobile/Task UX changes into the architecture refactor.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the current Runtime provider-selection and capability-policy entry points, then compare them with the proposed agent/internal/harness/contract.go and capabilities.go seam. Review the Pi and Codex cases in #421 and #426 before defining the smallest boundary. Done means Runtime uses one semantic seam, provider quirks are centralized, and deterministic tests protect the listed invariants.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100