Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/agents-harness.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: agents-harness

on:
push:
branches: [main]
paths:
- 'packages/codex-harness/**'
- 'scripts/*agents-harness.sh'
- 'services/agents-api/tests/native/*/source.json'
- '.github/workflows/agents-harness.yml'
- 'Makefile'
pull_request:
paths:
- 'packages/codex-harness/**'
- 'scripts/*agents-harness.sh'
- 'services/agents-api/tests/native/*/source.json'
- '.github/workflows/agents-harness.yml'
- 'Makefile'

permissions:
contents: read

concurrency:
group: agents-harness-${{ github.ref }}
cancel-in-progress: true

jobs:
native-build:
runs-on: ubuntu-22.04
timeout-minutes: 60
env:
CARGO_HOME: /home/runner/.parsar/cache/agents-harness-cargo
CARGO_TARGET_DIR: /home/runner/.parsar/cache/agents-harness-target
AGENTS_HARNESS_NATIVE_SOURCE: /home/runner/.parsar/references/codex-native
CARGO_BUILD_JOBS: 4
CARGO_PROFILE_DEV_DEBUG: 0
steps:
- uses: actions/checkout@v7
- name: Check packaging
run: make check-agents-harness
- name: Install native build prerequisites
run: |
sudo apt-get update
sudo apt-get install -y build-essential pkg-config libssl-dev
rustup toolchain install 1.95.0 --profile minimal --component rustfmt --component clippy
- name: Fetch the pinned upstream source
run: |
revision="$(python3 -c 'import json; print(json.load(open("packages/codex-harness/source.json"))["revision"])')"
git init "$AGENTS_HARNESS_NATIVE_SOURCE"
git -C "$AGENTS_HARNESS_NATIVE_SOURCE" fetch --depth 1 https://github.com/openai/codex "$revision"
- uses: actions/cache@v6
with:
path: |
~/.parsar/cache/agents-harness-cargo
~/.parsar/cache/agents-harness-target
key: agents-harness-${{ runner.os }}-1.95.0-${{ hashFiles('packages/codex-harness/source.json') }}
- name: Check native harness and independent release build
run: |
make check-agents-harness-native
make build-agents-harness
28 changes: 28 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,28 @@ Production adoption requires real remote execution/files/history acceptance plus
bounded idle ownership, caller authorization and stale-write fencing. Connection
observation generations alone cannot retract already-issued filesystem mutations.

The opt-in [private harness artifact](packages/codex-harness/README.md) consumes
that same hook in a separately named executable at the unchanged native pin.
Its canonical patch lives in the package; qualification manifests reference the
same bytes. Export the exact upstream commit, verify the lock normalization and
named-binary overlay, and retain source/toolchain/artifact provenance. Do not build
from a mutable upstream worktree or present this integration as a stock binary.
Capture operator selectors before native bootstrap; retain native dotenv/helper
initialization before threads and its alias guard until runtime teardown.
The existing Go RPC owns its raw stdio child. A private same-user local socket
offers metadata only through that runner's manager, with a frozen registry
Environment UUID, the adapter's native `remote` manager key, and no local fallback.
Keep socket admission bounded and close it with the runner. An unresolved native
metadata timeout must stop the owner before admitting another operation; client
frame/response timeouts are connection-local. Never equate dropping the native
response future with remote settlement. Bound Tokio runtime shutdown so an
uncancellable native stdin read cannot hide local process exit from the RPC owner.
The socket directory
must be new and private under `~/.parsar`; native/helper/socket selectors remain
operator configuration. Public feature admission and default daemon selection
are unchanged. Metadata path checks do not qualify filesystem isolation, idle
ownership, remote retirement, or the existing RPC's full backpressure behavior.

The private [raw Files composition](services/agents-api/tests/native/raw_files/README.md)
reuses the pinned native socket client and the same typed Files/registry fixture.
Record its fixture-only workspace dependency patch separately from the manager
Expand Down Expand Up @@ -2784,6 +2806,12 @@ Docker-free installer lifecycle checks, plus `make check-agents-api` for the
execution service. `make check-agents-executor` owns the optional native launcher's
locked unit tests, formatting and Clippy; `make build-agents-executor` independently
builds its release artifact. Native/model fixtures remain explicit acceptance checks.
`make check-agents-harness` adds lightweight exact-patch and packaging checks to
the full gate. Changes to the optional harness artifact also require
`make check-agents-harness-native` (locked native tests, formatting and Clippy),
`make build-agents-harness`, and the applicable actual executor/provider acceptance.
Those expensive native checks run separately and in path-selected CI; a packaging
pass alone is not native runtime acceptance.
Keep the subtargets aligned with
the full gate whenever the required checks change. Daemon-only changes must
trigger the same Go checks in CI as server changes.
Expand Down
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ dev: dev-db

# The full gate runs independent API tests once, after their isolated build.
check: GO_TEST_EXCLUDE = $(if $(strip $(GO_TEST_RUN) $(GO_TEST_ARGS)),,github.com/MiniMax-AI-Dev/parsar/services/agents-api/% github.com/MiniMax-AI-Dev/parsar/packages/agents-client/%)
check: check-go check-store check-web check-cli check-hygiene check-installer check-agents-api check-agents-executor
check: check-go check-store check-web check-cli check-hygiene check-installer check-agents-api check-agents-executor check-agents-harness
@printf 'Parsar harness checks passed.\n'

check-setup:
Expand Down Expand Up @@ -377,3 +377,13 @@ build-agents-executor:

check-agents-executor:
./scripts/check-agents-executor.sh

.PHONY: build-agents-harness check-agents-harness check-agents-harness-native
build-agents-harness:
./scripts/build-agents-harness.sh

check-agents-harness:
./scripts/check-agents-harness.sh

check-agents-harness-native:
./scripts/build-agents-harness.sh check
16 changes: 10 additions & 6 deletions contracts/agents-api/workspace-placement.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Ownership rules remain in [CONTRIBUTING.md](../../CONTRIBUTING.md#environment-ow
| Native pin | 0.153.4, commit `3d2ee51ca2d5db578f328aa75e20aa22c0197c9a` | SDK 0.3.269, native 2.1.269 |
| Public execution | `none` and the accepted `self_hosted` remote-executor profile | `none`, with built-in command/file tools disabled |
| Workspace placement | Separate native executor; harness cwd is not the remote workspace | Private typed factory binding inside a separately qualified outer placement; changing cwd alone is insufficient |
| Preparation | Ready before input promotion; Start retains the same native preparation | No workspace preparation capability yet |
| Preparation | Ready before input promotion; Start retains the same native preparation | Private SDK/Go prepare-start ownership is qualified; public workspace admission remains closed |
| History | Retained native history on the bound device, separately from executor workspace | Managed native state and exact resume; private workspace continuation has explicit real-provider acceptance |
| Files | A shared native manager was proven privately; production transport/lifetime composition remains missing | Native tools can access a local workspace; public Files and an authorized idle owner remain missing |
| Cancellation | Owned-command cancellation verified; auxiliary process cleanup still has a recorded failure | Private workspace factory acceptance checks cancellation and effect cessation; arbitrary escaped descendants are not qualified |
Expand Down Expand Up @@ -77,11 +77,15 @@ Specify idle capacity, expiry/revocation and release independently of Run
completion. Releasing transient credentials must not delete caller-owned files
or required native history. A replacement socket alone never authorizes overlap.

The pinned Codex raw app-server runner cannot inject the privately proven shared
manager. Its injectable in-process route can drop notifications on saturation.
A second connection, a larger downstream queue or host-local `fs/*` against a
remote workspace does not solve that production seam. Native core integration
or a maintained upstream entrypoint requires a separately accepted change.
The tracked exact-pin raw-runner hook now publishes its stock-built manager;
private Files/execution/cancel/history composition is qualified. The injectable
in-process route can drop notifications on saturation, while the maintained raw
socket client's consumer queue is unbounded. The optional private harness artifact
therefore uses stock raw stdio with the existing Go RPC and a separate local
metadata socket into the same manager. It does not create a second executor pair
or call host-local `fs/*` for a remote path. Patch ownership, exact builds and
acceptance are defined in the [artifact guide](../../packages/codex-harness/README.md).
This does not enable public Files, a reusable idle owner or full transport bounds.

## Acceptance and next slice

Expand Down
113 changes: 113 additions & 0 deletions packages/codex-harness/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Private Codex harness artifact

`parsar-codex-harness` is an opt-in Linux amd64 executable. It embeds the pinned
Codex raw stdio runner and exposes one private remote metadata operation through
the runner's own `EnvironmentManager`. The existing Go `JSONRPCClient` owns the
child and native execution transport. The metadata socket is local control IPC,
not another executor/Noise connection. Default daemon installation and public
feature admission are unchanged.

## Source and patch ownership

Parsar maintains this integration artifact. It is not the stock upstream binary.
`source.json` pins Codex 0.153.4 at
`3d2ee51ca2d5db578f328aa75e20aa22c0197c9a`, Rust 1.95.0, the manager hook and a
separate named-binary manifest overlay. The hook's canonical copy is
`patches/manager-exposure.patch`; the older native qualifications reference the
same file. Maintain its qualification and hash with every deliberate change.
Replace the hook when an equivalent maintained upstream entrypoint is selected
and independently accepted; never silently change the native pin.

Preparation exports that exact Git commit, ignoring checkout modifications. It
checks the original lock, normalizes only the 149 upstream workspace package
versions, checks the resulting lock, applies the two hashed patches and injects
`src/` into `codex-rs/app-server/parsar-harness/`. The named binary uses existing
app-server dependencies. No dependency resolution, client dependency or
third-party version change is part of the overlay. Mismatched identities fail.

## Build and checks

Install Rust 1.95.0 with rustfmt and Clippy, Python 3.10+, Git, tar, a C toolchain,
pkg-config and OpenSSL development headers on Linux amd64. Supply an existing
official Codex Git checkout containing the pinned commit:

```sh
export AGENTS_HARNESS_NATIVE_SOURCE="$HOME/.parsar/references/codex-native"
make check-agents-harness
make check-agents-harness-native
make build-agents-harness
```

`make check` includes the lightweight packaging checks. The explicit native check
prepares a fresh export and runs the binary's locked unit tests, formatting and
Clippy. Native checking and a release build are required for artifact changes;
they are intentionally separate from the ordinary local gate. CI runs both on
affected paths. Real executor/provider acceptance is separate from all build checks.

Builds and caches stay below `~/.parsar`. `CARGO_HOME`, `CARGO_TARGET_DIR` and
`AGENTS_HARNESS_BUILD_DIR` may override their defaults only within that root.
`RUSTUP_TOOLCHAIN` may select an installed alias; the build verifies that its
compiler reports exactly Rust 1.95.0.
The default output is `~/.parsar/build/agents-harness/parsar-codex-harness` beside
`provenance.json`. Provenance records the native commit, manifest, patches,
injected sources, prepared lock, toolchain and artifact hash. Acceptance must also
record the exact stock helper hash and check execution without the prepared source
tree present. Build provenance alone does not establish runtime compatibility.

## Private startup contract

The operator supplies these environment variables to the child:

| Variable | Meaning |
| --- | --- |
| `PARSAR_CODEX_HARNESS_NATIVE` | Absolute path to the stock native 0.153.4 helper |
| `PARSAR_CODEX_HARNESS_ENVIRONMENT` | One canonical remote Environment UUID |
| `PARSAR_CODEX_HARNESS_WORKSPACE` | Absolute workspace path on that executor |
| `PARSAR_CODEX_HARNESS_IPC_ROOT` | New private directory below the caller's `~/.parsar` |

The wrapper accepts the existing `-c` overrides and `app-server --stdio` with
`--enable`/`--disable` features. Unsupported options fail explicitly. Native
configuration and `CODEX_HOME` remain native concerns; provider credentials must
not be added to wrapper arguments. Public requests cannot select local process,
helper or socket targets.

The endpoint is `files.sock` within the new `0700` IPC directory, with mode `0600`
and a same-UID peer check. Existing directories or socket paths are not overwritten.
Each bounded connection carries one JSON line with `environment_id` and a relative
`path`. The identity must match startup configuration, and the manager entry must
be remote and ready. Startup also matches the operator UUID to the native registry
Environment variable. The native manager uses its fixed `remote` key, independently
of that UUID. A response reports native metadata or a safe error. There is
no local filesystem fallback and no read, write or listing method.

Startup freezes the operator binding before calling native `arg0_dispatch`. This
preserves native `CODEX_HOME/.env` credential loading and helper dispatch before
threads start, without letting dotenv replace private selectors. The native alias
guard lives until runtime teardown; explicit child re-execution uses the pinned
stock helper.

The request shares one ten-second deadline. A stalled frame or response writer
closes its connection. If the native operation has not settled by the deadline,
the artifact exits with an error and closes admission; dropping the native wait
does not cancel remote work. Recovery must retain that uncertainty and must not
infer remote retirement from this local failure. Runtime shutdown waits at most
one second for blocking tasks, including native stdin, so a caller keeping its
input pipe open still observes local process exit. This is not a remote cleanup
guarantee.

## Acceptance limits

Qualification must use this final binary through the existing Go RPC caller and
an actual authenticated remote executor. Native execution creates a file; metadata
is observed while idle, during execution, after cancellation and following fresh
process history continuation. Controlled tests cover startup/EOF, identity errors,
socket collision, oversized frames, stalled peers and early runner exit. Preserve
failed evidence and distinguish local child exit from remote mutation retirement.

Raw stdio avoids a typed-notification parser and preserves the native transport.
This does not mean the Go adapter stores unknown notifications or that every
existing RPC queue/write path is production-qualified. IPC frame, concurrency and
deadline bounds do not establish general native filesystem resource limits.
Metadata does not prove path isolation, public Files semantics, a reusable idle
owner, Core authority, successor safety or complete output fidelity. These remain
separate admission and acceptance work.
13 changes: 13 additions & 0 deletions packages/codex-harness/patches/artifact-target.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--- a/codex-rs/app-server/Cargo.toml
+++ b/codex-rs/app-server/Cargo.toml
@@ -15,6 +15,10 @@
[[bin]]
name = "exec-server"
path = "src/bin/exec_server.rs"
+
+[[bin]]
+name = "parsar-codex-harness"
+path = "parsar-harness/main.rs"

[lib]
name = "codex_app_server"
Loading