Codex Plugin

Run OpenLoomi from inside OpenAI Codex CLI. OpenLoomi is a local-first desktop app that holds your memory, runs tasks in the background, and talks to your connected apps (Gmail, Slack, GitHub, Calendar, Linear, …). This plugin turns Codex into a front-end for that local runtime — you chat with Codex, and Codex hands work off to OpenLoomi instead of doing everything itself.

You keep using Codex the way you already do. OpenLoomi runs next to it, on your machine.

What you can do with it

  • Ask Codex about your work. "What did I work on last Tuesday?" — Codex pulls the answer from OpenLoomi's local memory instead of guessing.
  • Hand tasks off for follow-up. "Send this to Loomi so it reminds me about it tomorrow" — the task goes into OpenLoomi's loop and pings you when it's ready.
  • Route Codex through OpenLoomi. When OpenLoomi answers, it can use your Codex CLI runtime under the hood, so you only configure one runtime.
  • Trigger OpenLoomi workflows from chat. Memory, loop, and connectors are all exposed as Codex skills — type @OpenLoomi … and go.

OpenLoomi still owns the heavy lifting: local memory storage, connector credentials, scheduled tasks, the desktop UI, secrets. Codex just gets a doorway into all of it.

Runtime implementation details (how OpenLoomi drives a Codex subprocess internally) live in Codex CLI Runtime. This page is about the external integration — how a Codex CLI user drives OpenLoomi.


Install

The OpenLoomi repository root doubles as a Codex marketplace root. It ships .agents/plugins/marketplace.json that points at plugins/codex/, so any Codex build that supports codex plugin marketplace can install the plugin directly.

From GitHub

codex plugin marketplace add melandlabs/plugins && codex plugin add openloomi@openloomi

Paste the whole line into a Codex shell — it adds the slim melandlabs/plugins marketplace and installs the openloomi plugin in one go. Codex fetches the repository, reads the marketplace manifest, and installs into ~/.codex/plugins/cache/openloomi/openloomi/<version>. Restart Codex and start a new thread so the cache is refreshed, then ask @OpenLoomi Run first-use setup. to wire up the desktop app.

From a local checkout (developers)

git clone https://github.com/melandlabs/openloomi.git && cd openloomi && codex plugin marketplace add . && codex plugin add openloomi@openloomi

To pick up local edits to plugins/codex/, force Codex to re-snapshot the marketplace:

codex plugin marketplace remove openloomi && codex plugin marketplace add . && codex plugin add openloomi@openloomi

Requirements

  • Codex CLI 0.144+ (anything that supports codex plugin marketplace).
  • For GitHub install: network access to github.com.
  • For local install: a writable checkout of the OpenLoomi repository.
  • OpenLoomi Desktop installed — or a source build that produces the OpenLoomi Desktop app — for anything beyond setup guidance and workflow discovery. Without it, the plugin can still report readiness and walk you through installation, but loop, memory, and connector tasks can't actually run.
  • Codex CLI on your PATH (e.g. brew install --cask codex or npm i -g @openai/codex) if you want OpenLoomi to route through your Codex runtime.

Walkthrough

The screenshots below are from a real end-to-end run. Follow them in order — every step is one Codex turn or one desktop app interaction.

1. Ask Codex to install the plugin

Ask Codex to install the plugin from the GitHub URL — no copy-pasting commands needed.

Install the plugin and setup https://github.com/melandlabs/plugins/tree/main/openloomi/codex

2. Add the marketplace

For the long-lived install path, add the marketplace once. Codex prompts for a source; enter melandlabs/plugins.

> codex plugin marketplace add melandlabs/plugins

3. Or launch Codex pointing at a local checkout

If you're hacking on the plugin (or running from source), point Codex at the directory and your edits are picked up live.

% codex --plugin-dir plugins/codex

4. Discover the skills

Type @OpenLoomi — Codex surfaces the skill namespace. The thin openloomi skill is the entry point, with sub-skills for openloomi-install (install / configure the desktop), openloomi-pet (pet state & themes), openloomi-memory (memory), openloomi-loop (loop dashboard), and openloomi-connectors (native connectors).

  • @OpenLoomi — read-only doorway into the local runtime
  • @OpenLoomi setup — install / launch / configure the desktop app
  • @OpenLoomi status — stable JSON status
  • @OpenLoomi pet <state> — set the Loomi Pet state
  • @OpenLoomi memory / @OpenLoomi memory <query> — local memory
  • @OpenLoomi loop — Loop dashboard snapshot

5. Run @OpenLoomi setup — readiness table lands in READY and the Loomi Pet appears

The install skill auto-chains install → launch → wait API → guest login. When it finishes, the bridge prints a small readiness table on the left and the Loomi Pet pops onto your desktop on the right in the fox theme with a Loomi is on watch badge. The pet is the file-watcher-driven widget — it doesn't talk to the bridge; it watches ~/.openloomi/pet-config.json and the assets/{fox,capybara}/ folders.

ItemStatus
Guest loginSuccessful
Runtime modepackaged
Version0.8.5
Local APIReachable
AI providerConfigured
Execution providerReady
Desktop processRunning
Final statusREADY

6. Right-click the Pet to open the context menu

The pet's context menu exposes Open Loomi / Settings / THEME (Fox ✓, Capybara) / Quit. The theme switch is hot-reload — the file watcher picks up activeTheme in pet-config.json within ~250 ms, and the bridge never writes these files.

7. Pick Capybara — the theme hot-reloads in place

The pet re-skins immediately. Same 9-state vocabulary (happy / idle / juggling / needsinput / presenting / sleeping / sweeping / thinking / working) — only the artwork changes. The readiness table on the left is unchanged.

7c. Drop in your own theme — kawaii cat via pet-custom/

The built-in themes are Fox and Capybara, but the pet watcher also auto-discovers any folder under ~/.openloomi/pet-custom/<name>/ with PNG state sprites. Drop a folder in, and the theme appears in the right-click menu within ~250 ms — no bridge call, no restart.

7b. Manually override the Pet state with @OpenLoomi pet

The hot-reload pet also accepts manual overrides from Codex. Type @OpenLoomi pet <state> and the bridge writes the new state to ~/.openloomi/pet/runtime_state.json; the file watcher picks it up and the sprite swaps within ~250 ms. Useful for "task done" beats where you want the pet to flip to happy between turns.

8. @OpenLoomi status returns the canonical JSON

For any triage or bug report, paste the JSON output verbatim. The shape never changes: mode / installed / version / tokenPresent / aiProviderConfigured / nativeRuntime / apiReachable / hooksInstalled / ready / nextAction / reason / source — with source: "codex-plugin" instead of "claude-plugin".

Step 8 — Codex verifies the live runtime via lsof -iTCP:3414 + curl /api/native/providers and the canonical OpenLoomi Status block confirms Running: Yes · PID 2320 · port 3414 · Healthy · Ready

9. Codex hooks — bundled by default, no install step

Unlike the Claude plugin (where /openloomi:hooks install is opt-in), the Codex plugin declares its lifecycle hooks in plugins/codex/hooks/hooks.json and they are bundled into every session automatically. The full event surface Codex maps to pet states:

Codex eventPet state set
SessionStartpresenting
UserPromptSubmitthinking
PreToolUseworking
PermissionRequestneedsinput
PostToolUsethinking
SubagentStartjuggling
SubagentStopthinking
Stophappy

Each handler is a thin node .../scripts/loomi-bridge.mjs state <name> --event <event> --quiet call with a 5s timeout. The bridge never blocks the Codex turn; if the runtime API is unreachable it logs a single line and exits 0.

10. Hooks status — confirm install

The Codex plugin's hooks are always-on, so the equivalent of "hooks status" is just @OpenLoomi status — the JSON reports hooksInstalled: true and source: "codex-plugin" whenever the hooks/hooks.json block is present in the loaded plugin.

You should see:

  • hooksInstalled: true
  • Plugin path: plugins/codex/hooks/hooks.json
  • source: "codex-plugin"
  • nativeRuntime: codex (when OpenLoomi is configured to use Codex as its agent executor)

If hooksInstalled is false, check that you launched Codex with --plugin-dir plugins/codex (or that the marketplace-installed copy shipped the hooks/ directory).

11. Connect your apps with @OpenLoomi connectors

The wizard walks you through three independent y/N choices: install the composio skill, enable Screen Memory (Preferences → Chronicle → Screen Memory in the desktop app), and connect a messaging connector (native 7 platforms via openloomi-connectors, or 1000+ via composio).

Before the wizard runs, Codex preflights openloomi-connectors — loads its workflow guidance, calls setup-status, and probes GET /api/loop/connectors to see what the runtime already knows.

Step 11b — preflight check: $openloomi:openloomi-connectors loads workflow-guidance + setup-status, then curl /api/loop/connectors returns the live connector state

12. After Composio connects — 6 active apps in your workspace

The next Codex turn can list what you're wired up to. In this run: Gmail, Google Calendar, Google Drive, GitHub, Linear, Slack — all through Composio, with the workspace org and test user echoed back.

Connected via Composio (6 active): Gmail, Google Calendar, Google Drive, GitHub, Linear, Slack
Org: timi_workspace · Test user: pg-test-…

The probe at this point showed all six toolkits reachable, with a happy Pet sprite reflecting the successful run.

Step 12 — Composio Connections block after the auth probe: Gmail / Google Calendar / Google Drive / GitHub / Linear / Slack all reported Connected (6 active), with the happy Pet sprite reflecting the success

Run note (real data, not a copy): the screenshots for step 12 and step 14 were captured in two different sessions. Step 12's probe landed cleanly with all six Composio apps connected. Step 14's probe was taken later, after the local Composio surface had gone unreachable (composio backend unreachable (DNS / ConnectionRefused)), so the Loop dashboard flipped every connector back to needs_setup. That isn't a regression — it's how the dashboard honestly reports a dead connector backend.

13. @OpenLoomi memory — see what's already in your local memory

The first time the memory skill is invoked in a session, OpenLoomi prints a short welcome banner with example queries ("Search all my memory for Project X" / "Show recent Gmail insights" / "What did I know about John in January?" / "List my knowledge-base documents" / "Remember that I prefer morning meetings" / "Find related insights for insight_xxx"). Codex then re-invokes it a few times to prime the search side before falling through to the digest.

Step 13a — first invocation of $openloomi:openloomi-memory: the welcome banner lists example queries, and Codex hammers the skill a few times before the digest returns

> @OpenLoomi memory

The command searches the local memory + knowledge base + insights and returns a digest of what OpenLoomi already knows. In this run, the digest is "Today's OpenLoomi Insights (UTC 2026-07-19)" pulled via list-insights --days=1, with a "From Loomi" callout ("Sarah's signature says 'Head of Product' — memory still says PM" — the same drift the Loop is about to surface as a CONTACT_UPDATE card), a Volume paragraph (200+ session-hook captures), a Timeline (latest first) list (17:06 / 17:05 Codex session 019f7b56 Stop hooks, 16:08 earlier Codex capture, 15:50 Claude Code session e80da64c final note "完成, 最后健全性检查", 15:28 Claude Code session aa64ea6f TypeScript type check passed, with more Codex captures spread across 14:xx–16:xx UTC), a Shape of every item paragraph (platform = codex | claude-code, importance / urgency = General, dedupeKey = null, description only carries the hook event, not the transcript), Takeaways at the end.

Step 13 — Today's OpenLoomi Insights (UTC 2026-07-19) digest: Volume / Timeline (latest first) / Shape of every item / Takeaways

This is the read-only doorway into OpenLoomi's local memory. For a deeper search, pass a query: @OpenLoomi memory <query>.

13b. Write to memory from Codex with add-memory

Reading is half the story — you can also write. From any Codex turn, invoke openloomi-memory add-memory "<text>" --file=<path> and the entry lands in ~/.openloomi/data/memory/<path>. The actual run captured here used the lower-level POST /api/insights route to add "Tom is my boss (manager → direct report)" with type: relationship and file: people/tom.md. The runtime created ~/.openloomi/data/memory/people/tom.md containing "Tom is my boss. Role: boss. Relationship: manager → direct report." and returned insight ID b5cde372-eb1b-4698-a4f0-bff6a26496f5. The entry is immediately searchable via search-memory "boss" or search-all "boss tom".

Step 13b — POST /api/insights writes "Tom is my boss (manager → direct report)" to people/tom.md; runtime confirms Insight created successfully with ID b5cde372-… and the file ~/.openloomi/data/memory/people/tom.md lands on disk

14. @OpenLoomi loop — see the Loop dashboard snapshot

> @OpenLoomi loop

The command hits GET /api/loop/state and returns the Loop dashboard: enabled status + last tick, counts (pending decisions / done / dismissed / signals seen), per-connector health (needs_setup / local-only / linked), prefs in effect (tick frequency, brief time, quiet-when-empty, desktop notifications, …), and actionable notes (e.g. "all 5 Composio-backed connectors share one failure: the local Composio surface isn't reachable — Loop can't pull signals until you bring the Composio backend back online").

Step 14 — Loop Dashboard: 0 of 6 connected, Composio backend unreachable (5/6), Obsidian local-only, stale last tick ~24h ago; prefs briefTime 09:00 / wrapTime 21:00 / intervalSec 600; implication = unblock the Composio backend first

This is purely a dashboard snapshot — the Loop never takes destructive actions from this command. For actions, the Loop pops cards in the desktop app (step 15) and you decide there.

15. The Loop starts surfacing decision cards in the desktop app

This is what the system looks like once it's humming. OpenLoomi's Loop is the proactive execution brain: it watches your connected signals, classifies them into decision types, and pops a card into the desktop app with the reasoning trace and the actions you can hit.

Every card has the same shape: Signal + Type + Received + Confidence at the top, the From Loomi explanation, the Reason 1 / Reason 2 evidence, and the action buttons at the bottom.

The Loop ships with these decision types out of the box:

Decision typeWhat it doesExample
RSVPReply Yes / No to a calendar invitation"Reverb Q3 review — Wed 10:00 PT, organizer Sarah, conflicts with standup"
IM_REPLYDraft a reply to a known contact"Alice is bumping the Q3 deck timeline — Thursday is close"
EMAIL_REPLYPre-draft an outbound email"Sarah needs the Q3 OKR draft status by Friday"
LINEAR_REVIEWTriage a Linear issue assigned to you"LIN-1234 (pet bubble drag-and-drop) is in In Review with you assigned"
REQUIREMENT_SYNTHESISCluster PRs/issues into a requirements doc"14 PRs/issues tagged loop/v0.9 — needs a single requirements doc"
RELEASE_PLANDraft a release plan from merged PRs"12 PRs merged since v0.8.5 — time to draft the v0.8.5 release plan"
CONTACT_UPDATEUpdate a contact record when memory drifts"Sarah's signature says 'Head of Product' — memory still says PM"
DOC_UPDATERefresh a stale doc for the next version"docs/getting-started.md is stale (42 days, pre-v0.8.5)"
REVIEW_PRSurface a PR waiting on your review"PR #220 (lifestyle image prompts) is waiting on your review"
DEADLINE_REMINDERSurface an upcoming due date"v0.8.5 release plan due Friday — 3 PRs blocking the cut"
TODOAdd a follow-up to your todo list"Bug: historical self-owned calendar events surface as fake RSVP decisions"
DIGEST (QUIET)Consolidate a flood of low-priority signals"8 GitHub notifications — none urgent individually, but here's the consolidated view"

A few examples in detail:

Loop card — IM_REPLY for an Alice follow-up

Loop card — IM_REPLY expanded into a full reply composer

Loop card — LINEAR_REVIEW for LIN-1234 "pet bubble drag-and-drop"

Loop card — REQUIREMENT_SYNTHESIS for 14 PRs/issues tagged loop/v0.9

Loop card — RELEASE_PLAN for v0.8.5 "classifier-rules UX + custom channels"

Loop card — CONTACT_UPDATE for Sarah Chen's new "Head of Product" role

Loop card — DOC_UPDATE for docs/getting-started.md (42 days stale)

Loop card — DRAFT_REPLY for the Q3 OKR status email

Loop card — DRAFT_REPLY expanded with Subject and Body reply editor

Loop card — REVIEW_PR for PR #220 "compose lifestyle image prompts"

Loop card — TODO for issue #382 "historical RSVPs misclassified"

Loop card — DIGEST (QUIET) consolidating 8 GitHub notifications

15b. From the card — Dry run / Edit / Run / Dismiss

The action row at the bottom of every card turns a recommendation into a real outcome. The exact buttons depend on the card type:

  • RSVP (calendar invitation): Attend (primary) · Decline (outline) · View original (ghost). Tap Attend or Decline and OpenLoomi fires your Yes / No straight back through the connected Google Calendar as a calendar_rsvp action — no opening the event yourself to click the RSVP buttons.
  • Reply / update cards (IM_REPLY, EMAIL_REPLY, REVIEW_PR, LINEAR_REVIEW, REQUIREMENT_SYNTHESIS, RELEASE_PLAN, CONTACT_UPDATE, DOC_UPDATE, DEADLINE_REMINDER, TODO): Dry run (outline) · Edit · Run (primary when ready) · Dismiss (ghost). Dry run previews the exact draft or plan without firing; Run schedules the action through the right connector — email_reply via Gmail, im_reply via Slack / iMessage, github_review via the GitHub Reviews API, linear_review via Linear, requirement_synthesis / release_plan / doc_update into the local knowledge base, contact_update into memory, todo into the local todo store.
  • Quiet digests (DIGEST / QUIET_DIGEST / github_notification): Mark as read only — read-only aggregations, nothing to execute.

Two affordances live outside the action row so they never collide with the decision itself:

  • Card-level Dismiss sits in the header kebab (three-dot menu). Dismissing a card never accidentally declines a meeting. A mute rule is created for that signal scope, so the same hint won't resurface today.
  • Cancel scheduled action appears for ~30 s after you tap Run / Attend / Decline. The action is queued as a cron job before it actually fires — Cancel stops it. A per-card audit history (under the technical details) records every attempt with its terminal state (completed / skipped / blocked / failed / cancelled / superseded), so contradictory responses (e.g. RSVP "No" then "Yes") appear side-by-side instead of overwriting each other.

If the underlying connector refuses (the runner returns blocked or failed), the action row stays open with a one-tap retry — the card never silently flips to done when nothing actually happened.

16. Register your own decision types

The Loop is extensible. Drop a PUT /api/loop/types against the local runtime and your custom card joins the queue.

TOKEN=$(cat ~/.openloomi/token | base64 -d)
curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  http://localhost:3414/api/loop/types \
  -d '{
    "id": "mom_imessage_alert",
    "label": "Mom iMessage",
    "icon": "👩",
    "actionKind": "todo",
    "description": "Triggers when mom sends an iMessage — surfaces as a high-priority todo so you never miss her"
  }'

17. The custom type fires on the next signal

The next iMessage from mom surfaces the new card with your icon, label, and a high-priority todo action.

Step 17 — MOM_IMESSAGE_ALERT custom type fires and surfaces a high-priority todo card


Auto-enable & first-use setup

Once installed via the marketplace the plugin is enabled automatically. Its primary skill (openloomi) and companion sub-skills are picked up from plugins/codex/.codex-plugin/plugin.jsonskills on the next Codex start. No additional registration step is required — mentioning @OpenLoomi (or any of the trigger phrases listed in the skill front-matter) routes into the bridge.

Drive the full first-use setup from a single command:

node plugins/codex/scripts/loomi-bridge.mjs setup

Or, from a Codex thread:

@OpenLoomi Run first-use setup.

The setup command is an auto-enable wizard that walks a small state machine in one invocation:

1. status_check       → read setup-status
2. install            → download + install OpenLoomi from the official
                        GitHub release (only when --yes/--confirm is set)
3. runtime_env        → write OPENLOOMI_AGENT_PROVIDER=codex to the host
                        GUI launchd / environment.d, or print Windows
                        user-environment guidance
4. launch_desktop     → open OpenLoomi Desktop and wait for the local API
                        to come up (configurable via --max-wait)
5. initialize-session → mint a guest/session token via the local API and
                        write ~/.openloomi/token
6. status_check       → final readiness check

The wizard stops early at any step that requires explicit user action:

  • Install requires --yes or --confirm. Without it, the wizard returns setup: "awaiting_user_action" with reason: "INSTALL_CONFIRMATION_REQUIRED". It will never download OpenLoomi silently.
  • AI provider configuration is never auto-run. Secret entry must happen in OpenLoomi-owned UI or interactive CLI surfaces. After the wizard finishes, status.aiProviderConfigured may still be false; in that case follow the configure-ai-provider guidance from the openloomi-install sub-skill.
  • Source checkout (SOURCE_FOUND_APP_NOT_BUILT) stops the wizard with nextAction: "build_or_install_openloomi". The plugin never builds OpenLoomi from source automatically.

The wizard returns structured JSON so Codex (or any other caller) can render each step:

{
  "ok": true,
  "setup": "ready",
  "steps": [
    { "step": "status_check", "ok": true, "reason": "INSTALL_REQUIRED" },
    { "step": "install", "ok": true },
    { "step": "runtime_env", "ok": true, "after": "codex" },
    { "step": "launch_desktop", "ok": true },
    { "step": "initialize-session", "ok": true, "tokenWritten": true },
    { "step": "status_check", "ok": true, "reason": "READY" }
  ],
  "status": {
    "installed": true,
    "appPath": "/Applications/OpenLoomi.app",
    "appRunning": true,
    "version": "openloomi-desktop 0.8.5",
    "tokenPresent": true,
    "executionProviderReady": true,
    "executionProviderSource": "native_codex_runtime",
    "ready": true,
    "nextAction": null
  },
  "message": "OpenLoomi is ready and the desktop app is wired to Codex."
}

Flags accepted by setup:

FlagEffect
--yes / --confirmAuthorize the install step when OpenLoomi is missing. Without it the wizard is read-only.
--max-wait <ms>How long to wait for the local API after launching the desktop app. Default 30000.
--non-interactiveFail fast instead of waiting for the local API. Useful in CI.

setup is idempotent — re-run it any time to recover from SESSION_INITIALIZATION_REQUIRED, re-apply OPENLOOMI_AGENT_PROVIDER=codex after a Codex upgrade wiped the launchd env, re-mint a guest/session token after deleting ~/.openloomi/token, or confirm that all steps still resolve to READY after an OpenLoomi Desktop upgrade. The wizard has a hard ceiling of 8 chained transitions per invocation.


Bridge commands

You can run any bridge command directly from a shell, without going through Codex. From the OpenLoomi source checkout:

node plugins/codex/scripts/loomi-bridge.mjs version
node plugins/codex/scripts/loomi-bridge.mjs setup-status
node plugins/codex/scripts/loomi-bridge.mjs workflow-guidance
node plugins/codex/scripts/loomi-bridge.mjs install-instructions
node plugins/codex/scripts/loomi-bridge.mjs install-openloomi --confirm
node plugins/codex/scripts/loomi-bridge.mjs initialize-session
node plugins/codex/scripts/loomi-bridge.mjs configure-ai-provider
node plugins/codex/scripts/loomi-bridge.mjs help

version prints the bridge identity, the current plugin phase, and the full command list:

{
  "name": "openloomi-codex-bridge",
  "version": "0.8.5",
  "pluginPhase": "runtime-provider-readiness",
  "commands": [
    "codex-runtime-info",
    "configure-ai-provider",
    "help",
    "initialize-session",
    "install-instructions",
    "install-openloomi",
    "pet",
    "run",
    "set-codex-runtime-env",
    "setup",
    "setup-status",
    "version",
    "workflow-guidance"
  ]
}
CommandDoesNotable failures
versionPrints bridge identity, plugin phase, and full command list
helpLists all bridge commands with usage
setup-statusStable readiness JSON — see Readiness contractINSTALL_REQUIRED, OPENLOOMI_API_UNREACHABLE
setupEnd-to-end first-use wizard (see above)awaiting_user_action, step_limit_reached
install-instructionsReturns platform-specific install guidance without performing the install
install-openloomiDownloads + installs OpenLoomi from the official GitHub release. Requires --confirmINSTALL_CONFIRMATION_REQUIRED
initialize-sessionMints a guest/session token via the local API and writes ~/.openloomi/tokenSESSION_INITIALIZATION_REQUIRED
codex-runtime-infoStructured JSON for the Codex-as-default-runtime switch plan, prerequisites, and companion env vars
set-codex-runtime-envWrites OPENLOOMI_AGENT_PROVIDER=codex to host GUI env (launchd / environment.d) or prints Windows steps
pet <state>Sets the Pet to a state (happy, thinking, …); see Pet mirrorINVALID_STATE, ENDPOINT_MISSING
stateStop-hook helper that archives session context into OpenLoomi memoryalways exits 0
archiveStop-hook payload reader that POSTs {type: "note", groups: ["codex"]} to /api/insightsalways exits 0
workflow-guidanceReturns structured guidance for the workflow skills (loop, memory, connectors, …)

Codex as default runtime

The packaged desktop app routes chat and agent requests through the Claude provider by default. To run the same desktop binary against the local Codex CLI instead, set OPENLOOMI_AGENT_PROVIDER=codex in the environment the desktop app actually inherits.

node plugins/codex/scripts/loomi-bridge.mjs set-codex-runtime-env codex
# macOS:   writes via launchctl setenv
# Linux:   writes ~/.config/environment.d/openloomi-codex.conf
# Windows: prints manual steps (System Settings → Environment Variables)

# Then quit and reopen OpenLoomi so the new env reaches the web server.

Flags accepted by set-codex-runtime-env:

FlagEffect
<value>Defaults to codex. Other supported values: claude, opencode, hermes, openclaw.
--unsetClear OPENLOOMI_AGENT_PROVIDER from the host environment.
--dry-runDescribe what would happen without performing the write.

macOS caveat: the desktop app's web server runs inside the GUI launchd session, not your terminal. export FOO=bar in a terminal does not reach the running web server. After setting the variable you must Quit and reopen OpenLoomi.app so the new env is inherited by the freshly forked web process. On Linux a per-user env file works after the next login, and on Windows you edit the user environment via System Settings.

For a permanent shell-side switch on macOS or Linux, append the export to your shell rc so future shells remember it:

echo 'export OPENLOOMI_AGENT_PROVIDER=codex' >> ~/.zshrc

The shell export helps the bridge itself; the set-codex-runtime-env step is what makes the GUI launchd domain and the desktop session pick the variable up.

Companion env vars

All read by apps/web's native-agent env resolver at startup:

VariableDefaultPurpose
OPENLOOMI_AGENT_CODEX_COMMANDcodexBinary to invoke (overrides PATH lookup)
OPENLOOMI_AGENT_CODEX_MODEL(none)Optional model override
OPENLOOMI_AGENT_CODEX_PROFILE(none)Optional -p <name>. Point this at a Codex profile that allows outbound network when connectors (Composio, Gmail, Slack, Linear, …) need to reach their backends. The runtime persists the choice in openloomi.config.toml; per-profile env vars live in codex-profile-env.plist (macOS) so the GUI launchd domain inherits them.
OPENLOOMI_AGENT_CODEX_SANDBOXworkspace-writeread-only | workspace-write | danger-full-access. Both read-only and workspace-write deny outbound network by default. Use OPENLOOMI_AGENT_CODEX_PROFILE to carve out a network-allowed profile instead of widening this to danger-full-access.
OPENLOOMI_AGENT_CODEX_ASK_FOR_APPROVALon-requestuntrusted | on-failure | on-request | never
OPENLOOMI_AGENT_CODEX_SKIP_GIT_REPO_CHECKtrueToggle Codex's working-directory git check
OPENLOOMI_AGENT_CODEX_FULL_AUTOfalseSet true to allow --full-auto under bypassPermissions
OPENLOOMI_AGENT_CODEX_TIMEOUT_MS120000CLI runtime budget in ms

Prerequisites that must hold before the desktop app will actually drive Codex:

  • which codex resolves to a working Codex CLI binary (install via brew install --cask codex or npm i -g @openai/codex).
  • ~/.codex/config.toml is configured and OPENAI_API_KEY (or the Codex CLI's other auth) is available to the spawned process.

Verification after launch: the desktop app's GET /api/native/providers should return codex inside agents and defaultAgent: "codex". If you still see defaultAgent: "claude" after running set-codex-runtime-env and reopening the app, the env change did not stick — re-run launchctl getenv OPENLOOMI_AGENT_PROVIDER in a terminal to confirm the GUI session actually has it.


Workflow skills

The plugin ships these sub-skills under plugins/codex/skills/:

SkillRole
openloomiMain entry point — triggers on OpenLoomi / Loomi mention and dispatches to the right sub-skill.
openloomi-installWalks install, first-use setup, AI provider setup, and SESSION_INITIALIZATION_REQUIRED recovery flows.
openloomi-loopRun attention-loop and follow-up workflows.
openloomi-connectorsCheck whether Slack, GitHub, Gmail, Calendar, and other sources are configured before acting. Reports status only.
openloomi-memorySearch or write memory through OpenLoomi-owned runtime surfaces. Thin wrapper — does not implement memory storage.
openloomi-apiOpenLoomi HTTP API reference (auth, chat, RAG, workspace, integrations, feedback). Triggered by API/backend questions.
openloomi-feature-guideProduct overview, capabilities, and how-tos for non-developer questions like "what can openloomi do".
composioThird-party 1000+ app integration router (Gmail, Slack, GitHub, etc.) via the Composio CLI. Platform-agnostic; not OpenLoomi business logic.

The workflow-guidance bridge command returns structured guidance for the three workflow skills (openloomi-loop, openloomi-memory, openloomi-connectors). All other skills are documentation or routing helpers. The plugin must not copy OpenLoomi connector, memory, or loop logic into Codex — runtime implementations stay inside the OpenLoomi desktop runtime.

Useful workflow prompts from a Codex thread:

@OpenLoomi Use the memory workflow to recall relevant context.
@OpenLoomi Use the loop workflow to plan the next step.
@OpenLoomi Check connector readiness for this task.
@OpenLoomi Hand this task to Loomi for follow-up.
@OpenLoomi Use Loomi to summarize the current task in one sentence.

Pet mirror hooks

Hooks are opt-in via plugins/codex/hooks/hooks.json (declared in .codex-plugin/plugin.json). They mirror Codex lifecycle events onto the OpenLoomi Pet without making authorization or control-flow decisions — best-effort UI feedback only. Memory archive, follow-up scheduling, permission decisions, and connector behavior stay inside OpenLoomi-owned runtime surfaces.

Codex eventPet state
SessionStartpresenting
UserPromptSubmitthinking
PreToolUseworking
PermissionRequestneedsinput
PostToolUsethinking
SubagentStartjuggling
SubagentStopthinking
Stophappy

Hooks use the same runtime-accepted source: "codex-plugin" value when posting to /api/pet/state. The state <state> --event <event> command is hook-safe: it never fails the Codex turn, never prompts, and returns hook: "skipped" when OpenLoomi is not ready, the token is missing, or the Pet endpoint is unavailable.

You can also drive the Pet directly from the bridge:

node plugins/codex/scripts/loomi-bridge.mjs pet happy
node plugins/codex/scripts/loomi-bridge.mjs pet working

The valid states are: happy, idle, juggling, needsinput, presenting, sleeping, sweeping, thinking, working.


Readiness contract

setup-status returns stable JSON that downstream tools (and the setup wizard) consume:

FieldMeaning
modepackaged | source | unconfigured
installeddesktop app found
appPathresolved OpenLoomi Desktop app path (e.g. /Applications/OpenLoomi.app)
appRunningwhether the desktop app process is currently running
versiondetected OpenLoomi version
tokenPresenta local auth token exists
sessiontokenPresent, guestBootstrapSupported, guestBootstrapMode
aiProviderConfigureda direct OpenAI-compatible or Anthropic-compatible AI provider is configured
aiProviderStatusruntime_configured | unavailable
executionProviderReadydirect AI provider or native Codex runtime can execute tasks
executionProviderSourceai_provider | native_codex_runtime | null
nativeRuntimeActive/api/native/providers reports Codex as the active default native runtime
nativeRuntimesummarized /api/native/providers probe result
connectorStatusAvailablewhether the local API can report connector status
apiReachablelocal HTTP API responded
readyeverything needed is in place
nextActionwhat to do next (see below)
checksdetailed provider / connector / runtime checks (e.g. aiProviderRuntime.providers[])

aiProviderConfigured: false does not necessarily block native Codex CLI execution. When /api/native/providers reports defaultAgent: "codex" and the Codex agent metadata is present, setup-status may still be ready: true with executionProviderSource: "native_codex_runtime". Direct AI provider settings remain relevant for features that explicitly use OpenLoomi-owned model-provider configuration.

nextAction values

ValueFix
install_openloomiInstall the desktop app.
provide_install_or_repo_pathProvide an explicit OPENLOOMI_INSTALL_DIR / OPENLOOMI_REPO_DIR.
build_or_stage_openloomi_ctlcd $OPENLOOMI_REPO_DIR/apps/web/src-tauri && cargo build --release.
initialize_openloomi_sessionRun setup so the bridge can mint a guest/session token.
open_openloomiLaunch the desktop app once so the local API can mint a session.
configure_ai_providerConfigure a model provider in OpenLoomi-owned settings.
configure_connectorsWire up Slack / GitHub / Gmail / Calendar sources as needed.
show_openloomi_skillsSurface workflow-guidance or the openloomi-* sub-skills.
return_without_bridgeNothing to do — return the result without crossing the bridge.
runReady. Run the task.

reason values

ReasonMeaning
READYAll checks passed.
OPENLOOMI_APP_INVALIDDiscovery resolved a path but it isn't a working OpenLoomi Desktop app.
SOURCE_FOUND_APP_NOT_BUILTSource checkout detected but the OpenLoomi Desktop app hasn't been built yet.
INSTALL_REQUIREDNo install discovered — install-openloomi --confirm is the next step.
OPENLOOMI_API_UNREACHABLEOpenLoomi is installed but the local HTTP API isn't responding on 127.0.0.1:3414/3515.
SESSION_INITIALIZATION_REQUIREDOpenLoomi is installed but ~/.openloomi/token is missing or unreadable.
CODEX_RUNTIME_ACTIVE / _INACTIVEStatus of the native Codex runtime the desktop app is currently using.
INSTALL_CONFIRMATION_REQUIREDInstall was requested without --confirm.
CONNECTOR_SETUP_REQUIREDOne or more connector sources are not configured.
INSTALLER_DOWNLOADED / AUTOMATIC_INSTALL_FAILEDInstall artifact download / verification / launch outcome.

OpenLoomi guest mode is supported. A missing token is not treated as a requirement for account registration. The bridge tries two guest endpoints in order:

  1. POST /api/remote-auth/guest — the JSON bearer flow. Preferred when the running build exposes it.
  2. POST /api/auth/guest?redirectUrl=/ followed by GET /api/auth/token using the Set-Cookie header — the legacy cookie-based flow. Falls back here only when the JSON endpoint returns 404 or is unreachable before any response, so a transient 5xx or empty payload on the JSON path still tries the cookie path before giving up.

Both paths write the same ~/.openloomi/token file and report session.tokenPresent: true.


Secret handling

Codex chat, argv, stdout, and stderr must never receive or print:

  • model provider API keys;
  • OAuth access tokens or refresh tokens;
  • connector app secrets;
  • OpenLoomi auth tokens;
  • local secure-storage contents.

The bridge may report only status-only fields such as:

OPENLOOMI_AUTH_TOKEN present/missing
~/.openloomi/token present/missing
guest/session initialization available/unavailable
AI provider configured/missing
AI provider runtime status available/unavailable
AI provider hasApiKey/baseUrl/model presence
connector configured/missing
local API reachable/unreachable

Example safe output:

{
  "aiProviderConfigured": false,
  "checked": [
    { "key": "OPENAI_API_KEY", "present": false, "source": "env" },
    { "key": "OPENAI_BASE_URL", "present": true, "source": ".env.local" }
  ]
}

The bridge may report key names and presence. It must not print values. The bridge may receive a guest/session token from the local OpenLoomi API only to write the standard ~/.openloomi/token file — it must keep the token out of argv, stdout, stderr, logs, and the Codex transcript.


Architecture

Codex
   → OpenLoomi Codex plugin
      → OpenLoomi skill entrypoint
         → loomi-bridge
            → discovery and install layer
            → first-use native runtime wiring layer
            → readiness layer
            → OpenLoomi skill guidance layer
            → optional Codex hook layer
            → OpenLoomi Desktop runtime (local HTTP API at 127.0.0.1:3414 / :3515)
                  → memory
                  → connectors
                  → loop
                  → model provider
                  → OpenLoomi Pet

The plugin stays thin. It calls OpenLoomi-owned runtime surfaces instead of copying connector, memory, or loop implementations into Codex.


Troubleshooting

  • OPENLOOMI_APP_INVALID — discovery resolved a path but it isn't a working OpenLoomi Desktop app. Reinstall or point OPENLOOMI_INSTALL_DIR / OPENLOOMI_APP at a valid bundle.
  • SOURCE_FOUND_APP_NOT_BUILT — the source checkout was detected, but the OpenLoomi Desktop app hasn't been built yet. Build it per apps/web/src-tauri/README.md, or install the packaged release.
  • OPENLOOMI_API_UNREACHABLE — the desktop app is installed but the local HTTP API isn't responding. Launch OpenLoomi Desktop and retry setup-status.
  • SESSION_INITIALIZATION_REQUIRED — OpenLoomi is installed but the local guest/session token could not be created. Open OpenLoomi Desktop once so the local API can mint a guest session, then re-run setup-status or setup.
  • AI_PROVIDER_REQUIRED / AI_PROVIDER_STATUS_UNAVAILABLE — prefer setting the OpenLoomi desktop runtime to Codex so OpenLoomi can reuse the user's existing Codex CLI runtime. If you choose a separate AI provider fallback, configure it in OpenLoomi Desktop. Secrets must stay in OpenLoomi-owned UI or secure storage. If the local API is unreachable, the plugin reports status as unavailable rather than falsely reporting missing configuration.
  • Codex still shows an old plugin version — remove and re-add the marketplace, restart Codex, and start a new thread. The cached plugin lives at ~/.codex/plugins/cache/openloomi/openloomi/<version>.
  • Pet control returns ENDPOINT_MISSING — non-blocking. The bridge returns a polite notice that the route is pending; Pet control resumes automatically once OpenLoomi ships it.
  • Pet control returns API_UNREACHABLE — no local API responded on 3414/3515. Start OpenLoomi Desktop and retry.
  • composio surface reachable reports unreachable from a Codex-driven session — Codex's workspace-write (and read-only) sandboxes deny outbound network by default, so the Codex subprocess that OpenLoomi spawns cannot reach Composio / Gmail / Linear / Slack and the connectors flip back to needs_setup. Fix it by giving OpenLoomi a dedicated Codex profile that allows outbound network while keeping file permissions at workspace-write, then set OPENLOOMI_AGENT_CODEX_PROFILE=<name>. The runtime persists the choice in openloomi.config.toml; per-profile env vars land in codex-profile-env.plist (macOS). Restart OpenLoomi Desktop so the next Codex spawn picks up the new profile. Do not widen OPENLOOMI_AGENT_CODEX_SANDBOX to danger-full-access for this — the profile carve-out is the supported path.