@open-matrix/codex-agent (1.1.32)
Installation
@open-matrix:registry=npm install @open-matrix/codex-agent@1.1.32"@open-matrix/codex-agent": "1.1.32"About this package
Codex agent
Owner: codex-agent / fleet operations. A Matrix peer wrapping the vendored Codex SDK.
Fleet workstream observations
session.start accepts optional explicit workstream metadata with schema
fleet.agent-workstream/v1, named agent, functionalArea, workstream, presence,
status, and optional blocker, handoff, suggestion strings. No registration means
no Blackboard row. Invalid supplied metadata returns FLEET_WORKSTREAM_METADATA_REQUIRED.
The session persists one observation ID and a monotonically increasing sequence with its
retained state. session.workstream.upsert {sessionId, workstream} requires valid metadata
and updates that same row; session.continue also accepts the object. Agent, area and
workstream cannot change after registration. Terminal turns publish inactive presence;
another turn reuses and reactivates the same row. session.workstream.end {sessionId,status}
marks a retained task's observation inactive without stopping its running turn. Smithers
calls it when the attempt ends. Disposal marks running observations orphaned and inactive.
Publication uses system.blackboard at default scope and a revision fence, through the
manifest's fleet.agent-workstreams transport import. Existing heartbeats reconcile
retained observations. Blackboard failure never gates a turn or task; these observations
confer no locks, dispatch authority or approval authority. See Smithers.
Application development sessions
development.session.start resolves the hivedock executable from the
checkout's @matrix/hivedock3-cli package declaration and starts it in the
application directory. Session state comes from the command's versioned JSON
lifecycle lines, never from human log text.
Each application's detached process PID and boot/start identity are atomically
recorded beneath <checkout>/.hivecast/development-sessions/. Raw stdout and
stderr are discarded. HiveDock instead writes only schema-validated lifecycle
records, with the shared credential redaction rule applied, to an owner-only
event log in that directory. The producer rotates it at 1 MiB independent of
line completion; the follower also bounds malformed partial input. On bootstrap the
development actor validates the application declaration and process identity,
reattaches a surviving session, follows that log, and discards stale or
interrupted records. A live child is signalled synchronously through its
verified handle; an adopted PID is signalled only after identity verification
and remains stopping until a later liveness check confirms its exit.
Development workspace
When deployment binds a checkout, the peer mounts <agent>.development. In addition to listing and
running a package's declared build, test, type-check and validate scripts, it creates packages
through the platform's shared package-artifact owner:
matrix invoke <agent>.development development.scaffold.application '{"name":"weather-desk","title":"Weather Desk"}'
matrix invoke <agent>.development development.scaffold.component '{"name":"status-pill","description":"A reusable status indicator."}'
matrix invoke <agent>.development development.package.build '{"package":"@matrix/weather-desk"}'
matrix invoke <agent>.development development.package.validate '{"package":"@matrix/weather-desk"}'
matrix invoke <agent>.development development.package.artifact '{"package":"@matrix/weather-desk"}'
matrix invoke <agent>.development development.session.start '{"application":"weather-desk"}'
Scaffolding accepts only a new kebab-case name and optional non-empty title and description. It never
normalizes a path-like name or overwrites a directory. Applications are placed under applications/;
reusable components are placed under libraries/ui-kit/; both are registered in the bound workspace.
Before returning, scaffolding links the new member's declared dependencies with lifecycle scripts disabled
and without changing the workspace lockfile, so the returned build and test operations are immediately usable.
The result's nextSteps lists the build, validation and, for applications, hot-reload operation.
After a successful build and validation, development.package.artifact returns only the package's
declared release files in the bounded byte shape accepted by store.release; it never publishes.
Session continuity
An ordinary broker outage does not end this package process or its Codex child. The runtime keeps reconnecting while the child continues its turn; once the broker returns, the same agent answers again and its session history is still available.
Session metadata and event history are written to one owner-only file per session beneath
<matrix-home>/data/agents/codex/<actor-mount>/sessions/. Changes are coalesced for 100 ms and
written with asynchronous file operations, file fsync, atomic rename, and directory fsync.
The store retains 50 sessions plus any additional active session or live restored orphan that
cannot be evicted safely, and the newest 100 events per session. When trimming at boot or making
room for a new session, it removes the oldest evictable record rather than discarding a live
orphan's fence.
Invalid whole-store files from the former sessions.json format are renamed with an
.invalid-<timestamp> suffix; invalid individual records are skipped, and a v2 record wins when a
legacy record repeats its ID. A configuration.json with invalid JSON or schema is likewise
renamed, never deleted. A file-system read error instead leaves the valid file in place. In both
cases the worker boots on deployed defaults and reports sessionPersistence.status as degraded
in worker.status. Boot cleanup removes only temporary files matching this store's atomic-write
names. An unreadable or unwritable store also degrades without taking the worker offline. After the agent
process itself restarts, any session that had an in-flight turn is listed as orphaned, with its
last Codex thread ID, direct child PID, and history; its durable record also retains the process
boot/start identity and executable. For a pre-upgrade PID-only record, the probe falls back to the
configured bundled Codex executable. A verified match makes session.resume return
SESSION_CHILD_STILL_RUNNING; a live PID that cannot be probed returns
SESSION_CHILD_UNVERIFIED. Both refuse to start a competing child, and a verified live orphan also
refuses ordinary session.stop because the actor has no safe handle with which to signal it. An
unverified child refuses ordinary stop as well; after a person checks the named PID, calling
session.stop with {"sessionId":"<session-id>","force":true} clears the durable guard and states
in its reply that it did not signal any process. An identity or command mismatch, or EPERM from
probing a PID owned by another uid, proves PID reuse and releases the fence. Capacity eviction
preserves verified and unverified live-orphan fences.
Once it exits, resume the session by passing its durable ID and a new prompt:
{"sessionId":"<session-id>","prompt":"continue from the last durable checkpoint"}
to session.resume. The actor derives the stored thread ID, reuses the session ID, retains the old
history, and appends the resumed turn. session.resume also accepts an explicit threadId for a
thread not already in the store. Resume IDs generated without a caller-supplied session ID use a
UUID, so a restart cannot collide with an earlier codex-resume-* record. session.continue
refuses an orphan with SESSION_ORPHANED so a caller cannot silently start without reattaching the
Codex rollout.
Authentication remains fail-closed. If reconnect receives two consecutive Authorization Violation replies (for example, the broker becomes reachable before its auth source), NATS treats
that close as terminal and the package supervisor restarts the peer. The restarted actor restores
the durable session as above; it does not bypass or retry through an authorization denial.
Peer bus continuity
An API key authenticates the peer's credential exchange; it is not the NATS credential
held for the process lifetime. matrix package run renews the issued bus credential at
four fifths of its measured remaining lifetime through the same refresher as the browser,
and the NATS reconnect callbacks read the fresh JWT and seed. The peer's HiveCast home also
holds its machine identity, so an abrupt same-machine restart can reclaim that mount's
volatile Registry lease without waiting for the dead process's lease to expire. A different
machine identity cannot take over the live lease.
At process start, the peer reads its repository source identity once. A bounded Git status excludes
untracked files, then a separately bounded ls-files presence check includes untracked changes
without walking their contents into Node's output buffer. worker.status and discovery heartbeats
reuse the captured codeCommit, codeDirty, and codeCommitAt; status polling never starts another
process. Installed peers without a readable Git checkout omit all three fields, log the startup
probe reason once, and continue to report their other status normally.
Machine-local auth health
self-check.run includes codex-auth-refreshable in the canonical development-readiness
checklist. credential.test uses the same checker and returns {ok:true,live,detail,codexAuth};
live is the credential verdict, while the outer ok means the operation answered.
status.get returns status.codexAuth; session.status returns codexAuth, including
when the requested session does not exist. The Fleet manager retains this object in
lastStatus, alongside the environment-scoped availability it verifies.
The metadata is {ok,lastRefresh,ageHours,mode,state,authFile,checkedAt,detail}.
No token, account email, auth-file content, or CLI stdout/stderr crosses the bus.
lastRefresh is normalized UTC; ageHours is rounded down (the guard compares exact
age); missing dates are null. state is ok, stale, or dead. checkedAt:null means
no explicit refresh has been proved for this login; a recent file alone is not proof.
API-key mode has no refresh lineage and is exempt from age refusal, explicitly without
a validity claim. External-token/keyring-only logins are outside this file-owned check.
Session runtime visibility
session.start and session.resume retain the merged model and
modelReasoningEffort that are actually passed to the Codex child. session.list
and session.status report those values for the life of the thread. A dispatcher may
also supply queueItem; it is persisted and returned by those projections.
config.get remains the peer default and may legitimately omit model when
dispatchers choose it per session.
session.result returns the latest terminal agent.result as a direct, typed
projection. Coordinators and applications use it instead of retrieving and parsing
session.history to find the agent's final report.
Fleet workspaces
workspace.prepare creates an absent owned checkout with git clone --reference, or
refreshes an existing clean checkout to origin/main, then configures the lane branch,
Git identity, and installed dependency closure. It refuses dirty files and clean local
commits not contained in origin/main; neither case is reset or stashed. Every process
is invoked with an argument vector rather than through a shell, using the same managed
toolchain environment as the agent's development commands rather than the host
process's ambient environment. workspace.describe
reports the checkout's branch, HEAD, dirty paths, and tracked diff stat.
When a Git or dependency command fails, workspace.prepare returns a bounded
workspace-command-failure/v1 diagnostic with the failed stage, exit or system code,
signal, killed/timeout facts, duration, and a credential-redacted output tail. Use that
evidence to repair the exact checkout; it does not authorize a blind retry or a wider
timeout.
The no-inference call is the vendored codex app-server --stdio with
-c 'cli_auth_credentials_store="file"', initialized over JSON lines, then:
{"id":2,"method":"account/read","params":{"refreshToken":true}}
The checker requires both a ChatGPT account response and an advanced last_refresh.
At 0.153.4 a transient refresh failure can return cached account data, so the response
alone is insufficient. No thread/turn/model call is issued; the utility is terminated
after its reply. Concurrent checks share one process; the existing 10-second
credential-test bound applies. See the OpenAI auth API
and pinned account processor.
Status polling reads metadata without rotating credentials. Configure positive
codexAuthMaxAgeHours in deployed runtime config or config.set (default 72), or set
CODEX_AGENT_AUTH_MAX_AGE_HOURS when starting the agent; deployed config wins.
session.start, session.resume, and session.run refuse stale/dead auth before
creating an SDK thread. Existing running sessions are not interrupted by age polling.
A recognized refresh failure marks status stale immediately and persists in the
existing self-check state file. A new local login timestamp or a successful explicit
refresh clears it. Failure text names the file and the exact cure:
codex login on this machine; do not copy another machine's auth.json
The September 9 fleet incident invalidated mac/ninja copies of one old refresh lineage together. Copying auth.json is the disease: refresh-token rotation/revocation can invalidate the other copies. Each machine or coding unit needs its own managed login home. The check detects stale/failed credentials; it cannot predict revocation of a currently valid lineage or prove that nobody copied a file.
Workstream metadata may include dependencies, an explicit array of nonempty workstream links.
The Fleet projection retains these coordination references without dispatching or gating peers.
Dependencies
Dependencies
| ID | Version |
|---|---|
| @open-matrix/contracts | 1.1.32 |
| @open-matrix/package-artifacts | 1.1.32 |
| @open-matrix/package-runtime | 1.1.32 |
Development Dependencies
| ID | Version |
|---|---|
| @matrix/test-utils | 1.1.32 |
| @open-matrix/core | 1.1.32 |
| @open-matrix/explorer | 1.1.32 |
| @openai/codex-sdk | ^0.163.0 |
| @types/node | ^25.0.10 |
| esbuild | ^0.25.0 |
| linkedom | ^0.16.11 |
| tsx | ^4.22.4 |
| typescript | 5.9.3 |
| vite | ^6.4.3 |
Peer Dependencies
| ID | Version |
|---|---|
| @open-matrix/core | 1.1.32 |