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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ heartbeat, adapter exports, and MCP stdio are delivery modes. Memory is recall,
not authority: retrieved context can inform a turn, but it never overrides the
current user, repo, or policy state.

For the shortest install-to-first-recall path, see [`docs/getting-started.md`](./docs/getting-started.md).

## Current Surface

This is the landed MVP surface today:
Expand Down
81 changes: 81 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Getting started

This guide connects Codex to the read-only `codex-memoryd` MCP server. The
recommended release-shaped path uses the native binary:

```zsh
# Future release command: the formula and release artifacts are not published yet.
brew install joshyorko/tools/codex-memoryd
codex-memoryd mcp codex apply
codex-memoryd mcp codex status
```

Restart Codex after applying the configuration, then call `memory_status` to
verify that the server starts and responds. `preview` and `status` inspect the
owned Codex MCP block; `apply` updates only that block and backs up the existing
Codex configuration before changing it.

## Opt in to the container launcher

Use the container runtime when Docker or Podman should launch the MCP image:

```zsh
codex-memoryd mcp codex preview --runtime container
codex-memoryd mcp codex apply --runtime container
codex-memoryd mcp codex status --runtime container
```

The CLI performs setup and does not pull an image or start a container during
`apply`. When Codex later starts the MCP server, the generated stdio command
launches the configured Docker or Podman image on demand. The default image is
`ghcr.io/joshyorko/codex-memoryd:latest`; `CODEX_MEMORYD_IMAGE` can override it.
The container mounts the parent directory of the persistent SQLite database at
`/data`, using the corresponding database filename inside the container. This
directory mount preserves SQLite sidecar files such as WAL and shared-memory
files. The database remains persistent host data; its exact path is determined
by the resolved configuration.
The selected database parent must already exist; run codex-memoryd init or
create the configured directory before previewing the container launcher.

Restart Codex after applying the container configuration and call
`memory_status` again. Docker or Podman must be installed and available to the
CLI and to Codex when the MCP server starts.

## Switch runtimes or remove the integration

Switch back to the native binary with:

```zsh
codex-memoryd mcp codex preview --runtime native
codex-memoryd mcp codex apply --runtime native
codex-memoryd mcp codex status --runtime native
```

Restart Codex and verify with `memory_status`. To remove only the owned
`codex-memoryd` MCP block:

```zsh
codex-memoryd mcp codex remove
codex-memoryd mcp codex status
```

Removing the MCP block, uninstalling the Homebrew formula, or removing the
container image does not delete the persistent memory database. Delete that
database separately only if you intentionally want to discard stored memory.
To uninstall the future-release Homebrew installation after removing the MCP
block, run `brew uninstall codex-memoryd`.

## Source-build fallback

If the future-release Homebrew command is unavailable, build the binary from a
checkout and use `target/release/codex-memoryd` in the commands above:

```zsh
cargo build --release
target/release/codex-memoryd mcp codex apply
target/release/codex-memoryd mcp codex status
```

Homebrew, release, image, tag, and tap artifacts are not published in this
feature slice. The Homebrew command above becomes usable only after a later
release and tap publication completes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Container MCP Launcher and Homebrew Onboarding

## Context

`codex-memoryd mcp codex preview|apply|status|remove` manages the owned Codex
MCP block. The global `--runtime native|container` option already parses for
these commands, but MCP config rendering always emits the native binary path.
Josh's current Codex config therefore points at a native binary that no longer
exists.

The repository also lacks a short release-user guide. The README contains
source-build, dogfood, daemon, and operator detail, but there is no minimal
Homebrew install-to-first-recall path. There are currently no repository tags,
GitHub releases, release workflow, or `homebrew-tools` formula for this binary,
so Homebrew instructions must be clearly described as the intended release
contract until those artifacts land.

## Decision

Make the existing global runtime selector authoritative for Codex MCP config
generation:

- `--runtime native` preserves the current direct-binary stdio entry.
- `--runtime container` emits a Docker or Podman stdio entry that starts the
Comment on lines +23 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Generate an upgrade-stable Homebrew binary path

Preserving the current direct-binary entry can persist a versioned Homebrew Cellar executable path; after brew upgrade removes that keg, Codex again points at a binary that no longer exists—the exact failure this design is intended to repair. The native Homebrew path should render a stable opt symlink or another durable launcher path, and the compatibility test should distinguish source-build behavior from Homebrew upgrades.

Useful? React with 👍 / 👎.

published image on demand and exits when Codex closes stdin.
- Omitting `--runtime` preserves the resolved/default native behavior.
Comment on lines +23 to +26

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Define behavior for every accepted runtime value

The repository's global RuntimeKind also accepts auto and compose-dev, and because the option is global those values already parse for mcp codex; they can also be selected through runtime environment resolution. This decision specifies only native and container behavior, leaving valid invocations to be silently treated as native/container or rejected inconsistently. Specify how auto resolves and whether compose-dev is mapped or rejected before config mutation, and cover both values in the CLI tests.

Useful? React with 👍 / 👎.


Do not add another runtime option under `mcp codex`. Because the root option is
global, both placements remain valid:

```zsh
codex-memoryd --runtime container mcp codex apply
codex-memoryd mcp codex apply --runtime container
```

The documentation will use the second form because it reads naturally at the
point where the choice matters.

## Generated Container Contract

The container MCP block uses the runtime already resolved by
`codex-memoryd`:

- command: resolved `docker` or `podman` executable
- transport: interactive stdio (`run -i`)
- lifecycle: ephemeral container (`--rm`)
- image acquisition: pull when missing (`--pull=missing`)
- image: resolved `CODEX_MEMORYD_IMAGE`, defaulting to
`ghcr.io/joshyorko/codex-memoryd:latest`
Comment on lines +47 to +49

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Refresh mutable latest images

When the default :latest image has already been cached, --pull=missing deliberately reuses that cached image, so upgrading the Homebrew CLI or publishing a newer release will not update the MCP server and users can remain on an old, potentially schema-incompatible binary indefinitely. Either generate an immutable version tag tied to the installed CLI or use an always-pull policy for the mutable latest default.

Useful? React with 👍 / 👎.

- identity: resolved host UID/GID so SQLite files remain host-owned
- storage: mount only the database's parent directory read-write at `/data`
- database argument: the corresponding `/data/<filename>` path
- MCP tier: explicit `mcp stdio --read-only`
Comment on lines +50 to +53

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass the resolved configuration into the container

Mounting only the database directory and passing only --db makes the container load configuration from its own home rather than the host's selected/default config. Unlike the native entry, it therefore loses configured default profile/workspace and other runtime settings, so an existing database can appear empty or behave differently whenever the user relies on non-default configuration. Pass the necessary resolved settings as arguments/environment, or mount the selected config read-only and reference its in-container path.

Useful? React with 👍 / 👎.


The existing Codex allowlist, approval mode, startup timeout, and tool timeout
remain unchanged. The database directory mount, rather than a single-file
Comment on lines +55 to +56

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Increase startup time for first-use image pulls

The container path pulls a missing image synchronously during MCP startup but explicitly preserves the existing 30-second startup timeout. On a first launch, downloading and unpacking the image can readily exceed that limit, causing Codex to abort the MCP server before onboarding completes even though the runtime is functioning normally. Give container entries a longer startup timeout or pull the image during an explicit setup step before Codex starts it.

Useful? React with 👍 / 👎.

mount, is required because SQLite may create WAL and shared-memory sidecars.

`preview` and `status` are read-only. `apply` mutates only the owned MCP table,
backs up an existing Codex config before changing it, and remains idempotent.
It does not pull the image or start a container; Codex does that when it starts
the MCP server.

## First-Time User Guide

Add a short `docs/getting-started.md` and link it near the top of the README.
The release-shaped native path is:

```zsh
brew install joshyorko/tools/codex-memoryd
codex-memoryd mcp codex apply
codex-memoryd mcp codex status
```

The guide then tells the user to restart Codex and call `memory_status`.
Homebrew-native is the recommendation because the installed artifact is
already available and requires no container runtime.

The opt-in container path is:

```zsh
codex-memoryd mcp codex preview --runtime container
codex-memoryd mcp codex apply --runtime container
codex-memoryd mcp codex status --runtime container
Comment on lines +82 to +84

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Initialize the bind source before onboarding Codex

For a first-time container user, the default database parent (~/.codex-memoryd) does not yet exist, and this sequence never runs codex-memoryd init; the design also states that apply mutates only Codex config and does not start the container. Consequently, Codex reaches the bind mount before the application can create the directory, causing the mount to fail or be created with ownership that prevents the requested UID/GID from initializing SQLite. Add an initialization/directory-creation step to this path or explicitly make apply create the validated database parent.

Useful? React with 👍 / 👎.

```

It explains that the Homebrew CLI performs setup while Codex subsequently
launches the MCP image on demand. The guide includes switching back to native,
uninstalling the MCP block, the persistent database location, and a concise
note that removing the MCP block or formula does not delete memory data.

The tap command is marked as a future release command until the formula and
release artifacts exist. Source-build instructions remain available from the
README but are not part of the primary user journey.

## Errors

Container rendering fails before config mutation when:

- neither Docker nor Podman can be resolved;
- the database has no usable file name or parent directory;
- UID/GID or mount values cannot be represented safely.
Comment on lines +98 to +102

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow removal when the container runtime is unavailable

If Docker or Podman has been uninstalled or is temporarily unavailable while the resolved runtime remains container, requiring container rendering to succeed before any config mutation prevents mcp codex remove from deleting the stale MCP block even though removal needs neither an engine nor an image. Exempt remove from container prerequisite resolution so cleanup remains possible in the failure scenario it is meant to recover from.

Useful? React with 👍 / 👎.


Errors name the failed requirement and give the next command or configuration
override. Runtime image-pull, permission, and container-start failures remain
visible as MCP startup failures from Docker or Podman; the generated arguments
must not suppress their stderr.

## Tests

Focused CLI tests prove:

- native output remains byte-for-byte compatible;
- container preview contains the resolved engine, image, identity, mount, and
in-container database path;
- Docker and Podman selections render deterministically;
- spaces and TOML-sensitive characters in host paths are escaped correctly;
- preview and status do not write;
- apply backs up and replaces a drifted block;
- repeated apply is idempotent;
- remove deletes only the owned block;
- missing container runtime and invalid database paths fail before mutation;
- CLI help continues to expose one global `--runtime` option.

Documentation checks assert that the short guide contains native install,
container opt-in, verification, switching, and uninstall/data-retention paths.

## Release Boundary

This slice makes the CLI and documentation release-shaped but does not publish
an artifact, create a GitHub release, modify `homebrew-tools`, or install the
formula. A later packaging slice must produce checksummed platform artifacts,
add the formula to the tap, test installation from the tap, and replace the
guide's future-release label only after those checks pass.
Loading