The cognitive-castle plugin provides local castle_* MCP tools, the castle
skill, and background capture of Codex conversations. The setup below was
verified with Codex CLI 0.156.1 on Linux. Shell examples use Bash; /hooks
and /mcp are commands inside the interactive Codex CLI.
For a new checkout:
git clone --branch develop https://github.com/Testimonial/cognitive-castle.git
cd cognitive-castle
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e .
castle --version
command -v castle
command -v castle-mcp
codex --versionIf you already have the checkout and a Python environment, run
python -m pip install -e . there instead. Both castle and castle-mcp must
be on the PATH inherited by Codex. Launch codex from the activated terminal.
A desktop application may inherit a different PATH.
The plugin does not install Python dependencies or download embedding models. Models may need an initial download before offline use. Core memory needs no external API key; optional LLM processing uses your existing provider settings.
If you already use Castle with Claude, keep the existing palace and model
configuration. The default palace is ~/.castle/palace; both clients can use it.
For first-time project setup, run castle init /path/to/project --no-llm and
follow the prompts. Project-file import is separate from conversation capture.
This route uses Codex's plugin-creator skill and its local helper scripts.
The examples assume they are installed at
~/.codex/skills/.system/plugin-creator/. If that directory is absent, ask Codex
to use its available plugin-creator skill for this checkout. The
MCP-only alternative below works without these helpers.
For the first installation, run from the repository root:
python ~/.codex/skills/.system/plugin-creator/scripts/create_basic_plugin.py \
cognitive-castle --with-skills --with-hooks --with-mcp --with-marketplace
cp -R .codex-plugin .mcp.json hooks skills ~/plugins/cognitive-castle/
python ~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py \
~/plugins/cognitive-castle
python ~/.codex/skills/.system/plugin-creator/scripts/read_marketplace_name.py
codex plugin add cognitive-castle@personal
codex plugin list --marketplace personal --jsonIf the helper prints a marketplace name other than personal, substitute that
name in the two Codex commands. An existing installation should use the update
steps below instead of scaffolding again.
Check that the list reports installed: true and enabled: true. The personal
catalog is ~/.agents/plugins/marketplace.json, its source package is
~/plugins/cognitive-castle, and Codex installs a cached copy. Editing a source
file in the checkout does not automatically refresh that cached plugin.
Fully exit and reopen Codex, then start a new thread to load the plugin.
Installing the plugin and trusting its hooks are separate steps. Codex requires review of each new or changed hook before it runs. See the official hook documentation.
Inside Codex CLI:
- Enter
/hooks. - Select PreCompact, then press Enter.
- Check
Source: Plugin - cognitive-castle@personaland the commandcastle hook run --hook precompact --harness codex. - Press t to trust that hook.
- Repeat for SessionStart and Stop.
The first screen lists event names, not a row named Cognitive Castle. Scroll down to find Stop. When these are the only hooks for each event, the expected state is:
| Event | Installed | Active | Purpose |
|---|---|---|---|
| SessionStart | 1 | 1 | Small memory capability reminder |
| Stop | 1 | 1 | Capture the current transcript after a turn |
| PreCompact | 1 | 1 | Capture the transcript before context compaction |
Installed: 1, Active: 0 means the hook is present but will not run; open its
details to check trust or disabled state. Additional plugins can increase counts.
Enter /mcp and check that castle connected. This checkout exposes 34 tools,
including castle_search, castle_get_drawer, castle_add_drawer,
castle_sue_review, and castle_sue_status. Restart an existing MCP connection
after updating the editable Castle installation to refresh its tool list.
For requirement reviews, ask Codex to select the relevant drawers, state the
decision, and call castle_sue_review; call castle_sue_status with its returned
run ID to read the dialogue and source links. SUE runs separately in the
background. Its default provider is local Ollama. Explicitly choosing
provider="codex" sends that selected bundle to the configured Codex provider,
using gpt-5.6-luna / low reasoning unless a model is supplied. Merely running
Castle inside Codex does not choose external processing. See the
complete SUE guide.
To test automatic capture, send a distinctive sentence, for example:
Castle capture check 2026-09-24: the copper owl is on the windowsill.
Let Codex finish its answer and allow the background hook to complete. In a subsequent turn, ask:
Use castle_search in fast mode to find my copper owl sentence, then retrieve the original drawer and show its wing and source. Do not file it manually.
For this repository, the expected wing is codex_cognitive_castle. Other
workspaces use codex_ followed by a normalized directory name. A retrieved
drawer containing the sentence and the correct transcript source confirms a
save. An active hook, a successful MCP connection, or a completed answer alone
does not confirm that capture finished.
Stop and PreCompact import only the transcript supplied by Codex, with
added_by=codex. They run asynchronously and preserve message text without
creating diary summaries. SessionStart does not import the transcript.
With the personal plugin enabled and its hooks trusted, start Codex in the new
project's root directory. Conversation capture uses the existing palace; no new
palace or per-project plugin installation is required. For /work/my-app, the
conversation wing is codex_my_app. SessionStart adds a small reminder to use
Castle; earlier project decisions are retrieved through memory tools when
needed, rather than loading the entire palace into every new conversation.
| Information | How it reaches Castle |
|---|---|
| Your prompts and the assistant's text replies | Stop captures the current transcript after a turn; PreCompact also attempts capture before compaction. This includes requirements, decisions, explanations, and code pasted into those messages. |
| Source code, README, specifications, and other project files | Explicit castle mine import, described below. The Codex capture hook does not scan the repository or watch file edits. |
| Tool calls/results, internal reasoning records, image/audio payloads, and system/developer-role instructions | The current Codex transcript parser does not import these record types. Text repeated in an ordinary user/assistant message is part of that message. |
| Entity references | After mining, local extraction can add names and mentioned_in links to the SQLite graph. These are source references, not verified facts. |
| SUE questions and findings | An explicitly requested review selects requirement drawers; results are stored separately under <palace>/.sue/runs/. Chat capture does not invoke SUE automatically. |
Capture reads the actual transcript, converts its message envelopes to a text
transcript, and splits it into exact slices of up to 800 characters without
summarizing message text. A local embedding is attached for retrieval and the
text is stored in LanceDB. Each drawer retains the source transcript path,
chunk order, ingest time, source revision, wing, room, and added_by=codex.
Rooms are assigned from keyword matches against the conversation; the fallback
is general. Capture is not restricted to selected "important" messages.
An unchanged source is skipped. When a transcript grows, the current importer appends a new revision of its normalized content and keeps older revisions; unchanged earlier passages can therefore occur in multiple revisions. It does not currently store only the latest appended message. Project grouping uses the directory basename, so two different directories with the same basename share a conversation wing; source transcript paths still distinguish their records.
Codex capture has no 15-message threshold. That threshold belongs to the separate Claude Stop hook. Background capture can fail or be cancelled when Codex exits; verify a completed save by retrieving its drawer and source. See the official hook lifecycle and background execution documentation.
Project files are imported separately:
castle mine /path/to/projectThe project miner selects supported text/code formats and respects .gitignore
by default. To file project sources alongside the example conversation wing,
use castle mine /work/my-app --wing codex_my_app. This is a one-time import;
rerun it when you want to capture subsequent file revisions.
The importer supports Codex rollouts using canonical event_msg turns or newer
response_item message records. In the latter format, developer/system messages
are excluded. Missing transcripts are a no-op. Transcript formats may change
between Codex versions, and background work can be interrupted.
To retry a specific transcript manually, use its actual path:
castle mine /absolute/path/to/rollout.jsonl --mode convos \
--wing codex_cognitive_castle --agent codexThis confirms manual import, not automatic hook execution. Choose the wing for that transcript's workspace. Do not substitute the whole sessions directory unless you intend to import all of it.
After updating your checkout, run from its root:
python -m pip install -e .
python ~/.codex/skills/.system/plugin-creator/scripts/read_marketplace_name.py
cp -R .codex-plugin .mcp.json hooks skills ~/plugins/cognitive-castle/
python ~/.codex/skills/.system/plugin-creator/scripts/update_plugin_cachebuster.py \
~/plugins/cognitive-castle
python ~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py \
~/plugins/cognitive-castle
codex plugin add cognitive-castle@personalUse the marketplace name printed by the helper. The cachebuster refreshes the
installed package without changing the repository's release version. Restart
Codex, open a new thread, and check /hooks again: changed definitions may need
new trust. The editable Python install uses this checkout directly; the cached
manifest, skill, and hook definitions still require the reinstall step.
| Symptom | Check or action |
|---|---|
No cognitive-castle row in /hooks |
Open PreCompact, SessionStart, or Stop; the plugin name appears under Source in the details. |
| Plugin installed but no automatic save | Verify all three hooks are active, then check for the actual drawer after a completed turn. |
No castle entry in /mcp |
Check codex plugin list --marketplace personal --json, then restart Codex with the plugin enabled. |
castle-mcp not found |
Activate the environment containing this checkout before starting Codex; inspect command -v castle-mcp. |
| MCP startup timed out after 30 seconds | Update the Python runtime from this checkout and restart Codex. Older code scanned the entire palace during the handshake; initialization now leaves statistics to castle_status. |
| MCP works, capture fails | Confirm castle is also on PATH. Inspect hook details/output and ~/.castle/hook_state/hook.log for capture errors. Legacy installations may use ~/.mempalace/hook_state/. |
| Hook files changed but behavior did not | Copy the files, run the cachebuster, reinstall, and start a new thread. |
No /hooks command |
Check codex --version and use a CLI version supporting lifecycle hooks. These instructions describe the CLI, not a desktop menu. |
castle-mcp waits for JSON-RPC on stdin; running it alone and seeing a startup
message is not a complete connection test. An old last_checkpoint file or the
castle_memories_filed_away tool reflects the diary checkpoint mechanism and is
not proof that the Codex transcript hook completed.
To expose memory tools without installing the plugin, add this to
~/.codex/config.toml:
[mcp_servers.castle]
command = "castle-mcp"Restart Codex and check /mcp. Use an absolute executable path if needed. This
configuration supplies tools only; it does not install the skill or capture
hooks. Use either this registration or the plugin's bundled MCP registration
for castle to keep configuration unambiguous.
The repository bundles .codex-plugin/plugin.json, .mcp.json,
skills/castle/, and hooks/hooks.json. Claude's separate .claude-plugin/
integration remains available. See the official
plugin packaging guide.
python -m pytest tests/test_codex_plugin.py tests/test_hooks_cli.py tests/test_normalize.py -qThese tests use synthetic transcripts. They check scoped capture, startup output, failure handling, and both rollout formats without reading personal memories. Successful unit tests do not substitute for the capture check above.