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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ external/*
*.tsbuildinfo
coverage/
*.tgz
.wrangler/
.env
.env.*
!.env.example
.dev.vars
.dev.vars.*
131 changes: 88 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
# codex-js

`codex-js` is an unofficial TypeScript port of the Codex runtime for building
Codex-backed web apps and interfaces.
Unofficial TypeScript packages for building Codex-backed web applications.

The workspace publishes two npm packages:
This workspace publishes:

- `@jrkropp/codex-js`: core client, server, runtime, and testing utilities.
- `@jrkropp/codex-js-react`: React chat UI, shadcn-compatible primitives, and CSS.

Examples show how a host application supplies credentials, storage, prompts,
tools, and routes.
- `@jrkropp/codex-js`: browser client, server app-server helpers, runtime contracts, stores, model transport, and testing utilities.
- `@jrkropp/codex-js-react`: React chat UI, hooks, shadcn-compatible primitives, and generated CSS.

This project is not affiliated with, endorsed by, or sponsored by OpenAI.

## Install

```bash
pnpm add @jrkropp/codex-js
```sh
npm install @jrkropp/codex-js
```

For React UI:
For the packaged React UI:

```bash
pnpm add @jrkropp/codex-js @jrkropp/codex-js-react react react-dom
```sh
npm install @jrkropp/codex-js @jrkropp/codex-js-react react react-dom
```

```tsx
Expand All @@ -31,7 +27,11 @@ import { CodexChat } from "@jrkropp/codex-js-react";
import "@jrkropp/codex-js-react/styles.css";

const appServer = createCodexAppServerClient({
url: async () => getCodexAppServerWebSocketUrl(),
url: async () => {
const response = await fetch("/api/codex/session", { method: "POST" });
const { webSocketUrl } = await response.json();
return webSocketUrl;
},
});

export function Chat({ threadId }: { threadId: string }) {
Expand All @@ -41,52 +41,97 @@ export function Chat({ threadId }: { threadId: string }) {

## Public Surfaces

- `@jrkropp/codex-js`: small root client conveniences.
- `@jrkropp/codex-js/client`: browser app-server WebSocket client and protocol event helpers.
- `@jrkropp/codex-js/server`: Codex runtime, app-server processors, stores, model transport, and server helpers.
- `@jrkropp/codex-js/testing`: test stores and package test helpers.
- `@jrkropp/codex-js-react`: React chat components, hooks, render state, and composer helpers.
- `@jrkropp/codex-js-react/shadcn`: optional shadcn primitives for chat layout composition.
- `@jrkropp/codex-js-react/styles.css`: generated package CSS.
Core package:

- `@jrkropp/codex-js`
- `@jrkropp/codex-js/client`
- `@jrkropp/codex-js/server`
- `@jrkropp/codex-js/testing`

React package:

- `@jrkropp/codex-js-react`
- `@jrkropp/codex-js-react/shadcn`
- `@jrkropp/codex-js-react/styles.css`

There are no public upstream mirror or unstable imports.

## Server Shape

```ts
import {
createCodexAppServer,
createModelClient,
defineDynamicTool,
dynamicToolResponse,
} from "@jrkropp/codex-js/server";
import { InMemoryThreadStore } from "@jrkropp/codex-js/testing";

const lookupDeployment = defineDynamicTool({
name: "lookup_deployment",
description: "Look up deployment status.",
inputSchema: { type: "object", properties: {}, additionalProperties: false },
async execute() {
return dynamicToolResponse.text("Deployment is healthy.");
},
});

const appServer = createCodexAppServer({
threadStore: new InMemoryThreadStore(),
dynamicTools: [lookupDeployment],
defaults: {
cwd: "/workspace",
model: "gpt-5-mini",
modelProvider: "openai",
},
createModelClient({ session, threadId }) {
return createModelClient({
apiKey: process.env.OPENAI_API_KEY!,
installationId: "my-app",
sessionId: session.id,
threadId,
});
},
});
```

Host applications own HTTP routing, authentication, persistence, credentials, and platform bindings. `codex-js` owns the Codex app-server protocol, connection processing, runtime contracts, and dynamic tool mapping.

## Development
## Examples

```bash
```sh
pnpm install
pnpm external:sync --codex /path/to/codex --t3 /path/to/t3-chat
pnpm dev:node-local
pnpm dev:cloudflare-example
```

`examples/node-local` is the smallest full-stack local path: Vite, a Node WebSocket endpoint, `createCodexAppServer`, `createCodexAppServerConnection`, in-memory threads, and example dynamic tools.

`examples/cloudflare` is the deployable production-style path: plain Vite React, Worker API, Durable Object SQLite storage, one-time WebSocket tickets, hibernating Durable Object WebSockets, and server-executed dynamic tools.

## Checks

```sh
pnpm typecheck
pnpm lint
pnpm build
pnpm test
pnpm test:pack
pnpm build
pnpm publint
pnpm pack:dry-run
pnpm dev:minimal
pnpm build:examples
```

Upstream reference source should stay local and unchecked-in under
`external/`. The recommended setup is to sync local Codex and T3 source trees
into `external/codex` and `external/t3code` with `pnpm external:sync`, then keep
publishable package code inside the tracked `packages/*/src` trees.

## Releases

This repo uses Changesets. Add a changeset for user-visible changes:

```bash
```sh
pnpm changeset
```

Merging the Changesets release PR updates `CHANGELOG.md`, bumps package
versions, publishes to npm, and creates the GitHub release.

Releases use npm trusted publishing. Existing package names can publish through
OIDC from `.github/workflows/release.yml`; brand-new package names must be
bootstrapped once with an npm token or a manual first publish before trusted
publishing can be configured for them. Run `pnpm release:preflight` to catch
that state before a release can partially publish.
Merging the Changesets release PR updates changelogs, publishes to npm, and creates the GitHub release. Releases use npm trusted publishing through GitHub Actions.

## License And Attribution

`codex-js` is licensed under Apache-2.0. Portions are modified TypeScript ports
of OpenAI Codex, which is also Apache-2.0. T3-derived UI code is used under the
T3 Tools MIT license. See `LICENSE` and `NOTICE`.
`codex-js` is licensed under Apache-2.0. Portions are modified TypeScript ports of OpenAI Codex, which is also Apache-2.0. T3-derived UI code is used under the T3 Tools MIT license. See `LICENSE` and `NOTICE`.
26 changes: 13 additions & 13 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,20 @@ This documentation describes the intended production design of `@jrkropp/codex-j

- Establish durable primitives before implementation details.
- Keep the public model small, standard, and composable.
- Treat `src/upstream/codex-rs` as a Codex-shaped upstream source and `src/upstream/t3code` as a T3-shaped upstream source. Codex and T3 are proven source references; follow their folder structure, naming, concepts, classes, contracts, and lifecycle patterns as closely as practical.
- Keep package-owned abstractions outside the upstream trees.
- Treat `external/codex` as the Codex terminology and lifecycle source of truth.
- Keep publishable package code semantic and boring: `client`, `server`, `testing`, `internal`, `generated`, `components`, `hooks`, and `shadcn`.
- `ThreadStore` is the storage boundary. Product grouping, account boundaries, workspace selection, and deployment placement are not package primitives.
- Runtime delivery follows Codex's server names: `OutgoingMessageSender`, `ThreadScopedOutgoingMessageSender`, `ThreadState`, and `ThreadStateManager`.
- Examples use the public doorways: `CodexChat`, `createCodexAppServerClient`, `CodexAppServerMessageProcessor`, `createCodexAppServerRuntime`, `ThreadStore`, `createModelClient`, and `sendOutgoingMessage`.
- Examples use the public doorways: `CodexChat`, `createCodexAppServerClient`, `createCodexAppServer`, `ThreadStore`, `createModelClient`, and dynamic tool helpers.
- When behavior is wrong or unclear, compare against Codex or T3 first. If local code differs, realign it with the source reference instead of inventing a custom fix.
- Prefer precise names over broad abstractions.
- Separate accepted docs from staged thinking.
- Keep implementation and refactor plans in `plans/`, not in accepted architecture docs.

## Source References

- Codex source reference: `/Users/justinkropp/Github/host-app/external/codex`
- T3 source reference: `/Users/justinkropp/Github/host-app/external/t3code`
- Package Codex upstream source: `/Users/justinkropp/Github/host-app/packages/codex-js/src/upstream/codex-rs`
- Package T3 upstream source: `/Users/justinkropp/Github/host-app/packages/codex-js/src/upstream/t3code`
- Codex source reference: `/Users/justinkropp/Github/codex-js/external/codex`
- T3 source reference: `/Users/justinkropp/Github/codex-js/external/t3code`

The `external/` directories are read-only. Do not import from them, edit them, or treat them as package source.

Expand All @@ -38,12 +36,14 @@ The `external/` directories are read-only. Do not import from them, edit them, o

## Folder Structure

- `src/upstream/codex-rs/`: Codex-shaped upstream source tree.
- `src/upstream/t3code/`: T3-shaped upstream source tree.
- `src/runtime/`: platform-neutral Codex lifecycle code and contracts.
- `src/components/`: stable public React component surface.
- `src/hooks/`: stable public React hooks.
- `src/testing/`: package and consumer testing utilities.
- `packages/codex-js/src/client/`: browser app-server client facade.
- `packages/codex-js/src/server/`: platform-neutral app-server helpers.
- `packages/codex-js/src/testing/`: package and consumer testing utilities.
- `packages/codex-js/src/internal/`: implemented Codex ports and package internals.
- `packages/codex-js/src/generated/`: generated protocol surfaces.
- `packages/codex-js-react/src/components/`: stable public React component surface.
- `packages/codex-js-react/src/hooks/`: stable public React hooks.
- `packages/codex-js-react/src/shadcn/`: shadcn-compatible primitives.
- `start-here/`: short onboarding path for the package model, philosophy, and primitives.
- `architecture/`: accepted architecture notes and deeper system explanations.
- `design/decisions/`: accepted ADR-style decisions.
Expand Down
29 changes: 19 additions & 10 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,27 @@ Exploratory proposals live in [Staging](./staging/README.md) until their termino
## Package Source

```text
src/
upstream/
codex-rs/
t3code/

runtime/
components/
hooks/
testing/
packages/
codex-js/
src/client/
src/server/
src/testing/
src/internal/
src/generated/

codex-js-react/
src/components/
src/hooks/
src/shadcn/
src/styles.css

external/
codex/
t3code/
```

The source structure is accepted in [ADR 0001](./design/decisions/0001-package-source-structure.md).
Publishable source lives in `packages/*/src`. Source reference material lives in
`external/` or `docs/internal/` and is not part of the npm package surface.

## Documentation Areas

Expand Down
60 changes: 34 additions & 26 deletions docs/design/decisions/0001-package-source-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,52 @@ Status: accepted

## Context

`@jrkropp/codex-js` is a Codex runtime and UI kit. The package needs a source layout that makes upstream source trees obvious, keeps package-owned runtime code separate, and lets consuming applications extend behavior without editing package source.
The workspace publishes a core Codex SDK and a separate React UI package. The
source layout should look like a conventional npm workspace, not like an
extracted application or a public mirror of reference repositories.

Codex and T3 are source references. Their folder structure, naming, concepts, classes, contracts, and lifecycle boundaries are preserved as closely as practical so updates can be ported by comparing the corresponding source files.
Codex remains the terminology and runtime source of truth, but reference
material belongs outside publishable package source.

## Decision

The package source is organized around upstream source trees, a package-owned runtime, React components, React hooks, and testing utilities.
The workspace uses two packages:

```text
src/
upstream/
codex-rs/
t3code/

runtime/
components/
hooks/
testing/
packages/
codex-js/
src/client/
src/server/
src/testing/
src/internal/
src/generated/

codex-js-react/
src/components/
src/hooks/
src/shadcn/
src/styles.css
```

`src/upstream/codex-rs` is the Codex-shaped runtime upstream source. `src/upstream/t3code` is the T3-shaped chat UI upstream source. Code in these trees follows upstream names, file boundaries, contracts, and lifecycle patterns.
`packages/codex-js` is dependency-light and non-React. It owns browser client
helpers, platform-neutral app-server helpers, runtime contracts, store
contracts, model-client creation, dynamic tool mapping, and testing utilities.

`src/runtime` contains package-owned, platform-neutral Codex lifecycle code and contracts. It does not depend on React, routing, Cloudflare, Durable Objects, host application projects, or host-app business behavior.
`packages/codex-js-react` owns React components, hooks, shadcn-compatible
primitives, generated CSS, and React-only dependencies.

`src/components` contains the stable public React component surface built from the T3 upstream source. Developers import application-facing chat components from `components` rather than from the upstream tree.

`src/hooks` contains the stable public React hooks that bind a configured runtime to React applications. Hooks stay separate from components so developers can use the runtime with their own UI.

`src/testing` contains test utilities and lightweight helpers for package consumers and package tests.

Platform-specific implementation details are not source primitives. Cloudflare Workers, Durable Objects, browser storage, routing, credentials, tools, prompts, and product-specific renderers live in consuming applications or documentation guides.
Reference and parity material lives in `external/`, `reference/`, or
`docs/internal/`. It is not exposed through package exports or included in npm
tarballs.

## Consequences

Upstream-shaped code is visually isolated from package-owned code. Package-owned abstractions stay outside the upstream trees.

The package remains replaceable. Consuming applications extend behavior through composition, contracts, slots, renderers, tools, prompts, storage, and app-server boundaries instead of modifying package source.
Public imports are boring and semantic. Consumers use `/client`, `/server`,
`/testing`, the React package root, `/shadcn`, and `/styles.css`.

A Durable Object is one possible implementation of a Codex store and app-server boundary. It is not a primitive of the Codex assistant package.
Cloudflare Workers, Durable Objects, local files, databases, credentials, auth,
prompts, and product-specific tools remain host application concerns.

When behavior is wrong or unclear, the first step is to compare against Codex or T3 and realign the package with the corresponding source reference.
When behavior is wrong or unclear, compare against Codex terminology and
lifecycle concepts, then implement the package-facing API in the conventional
package folders.
14 changes: 9 additions & 5 deletions docs/design/decisions/0002-core-runtime-boundary.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ Core `EventMsg` values are runtime and storage internals. App-server implementat

React chat state reduces generated app-server protocol events into `ThreadEventStore`. Hooks and components render `ThreadEventSnapshot` state derived from generated `Thread`, `Turn`, `ThreadItem`, `ServerNotification`, and `ServerRequest` values. Core events remain below the app-server boundary.

Protocol state belongs in `src/runtime`; T3 projection belongs at the component boundary. The runtime reducer does not import T3 timeline types. Components create `CodexChatRenderState` from protocol snapshots and lifecycle UI state before rendering the T3-derived timeline, composer, banners, and pending-request slots.
Protocol state belongs in the core package runtime internals. React projection
belongs in `@jrkropp/codex-js-react`. Components create
`CodexChatRenderState` from protocol snapshots and lifecycle UI state before
rendering the timeline, composer, banners, and pending-request slots.

The package model uses Codex-shaped terms:

Expand Down Expand Up @@ -57,10 +60,11 @@ Product grouping, account boundaries, workspace selection, and deployment placem

The package layers remain explicit:

- `src/upstream/codex-rs` is the faithful Codex runtime upstream source.
- `src/runtime` contains platform-neutral lifecycle contracts around Codex concepts.
- `src/components` contains the stable T3-derived React component surface.
- `src/hooks` contains React hooks around a configured runtime.
- `packages/codex-js/src/client` contains browser app-server client helpers.
- `packages/codex-js/src/server` contains platform-neutral app-server helpers.
- `packages/codex-js/src/internal` contains implemented Codex ports and internals.
- `packages/codex-js-react/src/components` contains the stable React component surface.
- `packages/codex-js-react/src/hooks` contains React hooks around a configured app-server client.
- The consuming app owns storage, routing, auth, tools, prompts, product renderers, and deployment.

The app server runs Codex. The store remembers Codex. The UI renders Codex as generated app-server snapshots and live events.
Expand Down
Loading
Loading