i365dev / i365dev/free4chat

architecture(agent): establish a Free4Chat-owned Harness semantic compatibility layer

Closed
#427 4 comments 0 reactions 0 assignees View on GitHub

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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.