This document describes the recommended async integration between OpenClaw, GeodeCLI, and Geode.app.
Architecture:
GeodeCLI: the CLI entry called by OpenClaw.Geode.app: the worker app, launched with --worker.group.com.privycloudless.privyecho.If the Geode app is not installed, OpenClaw should guide the user to install it from the Mac App Store:
https://apps.apple.com/app/apple-store/id6752685916?pt=127800752&ct=openclaw&mt=8Both GeodeCLI and Geode.app use the same App Group container:
group.com.privycloudless.privyecho~/Library/Group Containers/group.com.privycloudless.privyecho/~/Library/Group Containers/group.com.privycloudless.privyecho/CLIInbox/~/Library/Group Containers/group.com.privycloudless.privyecho/CLITasks/~/Library/Group Containers/group.com.privycloudless.privyecho/CLITranscriptions/If the source audio is outside the shared container, copy it into CLIInbox/ first.
OpenClaw should call the bundled GeodeCLI:
bash
"/Applications/Geode.app/Contents/Helpers/GeodeCLI" --enqueue-transcription \
--audio "/Users/.../Library/Group Containers/group.com.privycloudless.privyecho/CLIInbox/audio.m4a" \
--language zh \
[--format txt|md|docx] [--summary]
GeodeCLI auto-detects the enclosing Geode.app and launches Geode --worker automatically.
Only during development or non-default installs, you may need:
bash
"/path/to/GeodeCLI" --enqueue-transcription \
--audio "/Users/.../CLIInbox/audio.m4a" \
--language zh \
--app-bundle "/path/to/Geode.app"
Behavior:
--audio per task.GeodeCLI persists a task JSON file into the App Group container.GeodeCLI launches Geode --worker and returns immediately.TASK_ID=<uuid>0Example:
text
TASK_ID=123e4567-e89b-12d3-a456-426614174000
stderr: Error: <CODE> plus optional English detail lines1: runtime error2: invalid argumentsCommon async-specific codes:
TASK_CREATE_FAILEDTASK_READ_FAILEDWORKER_LAUNCH_FAILEDAfter receiving a task id, OpenClaw should poll:
bash
"/Applications/Geode.app/Contents/Helpers/GeodeCLI" --task-status 123e4567-e89b-12d3-a456-426614174000
stdout: one JSON object0Example:
json
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"recordingId": "6a9b17c5-6c9d-4f0b-8401-f0d7f06a5e48",
"audioPath": "/Users/.../Library/Group Containers/group.com.privycloudless.privyecho/CLIInbox/audio.m4a",
"language": "zh",
"outputFormat": "txt",
"summarize": true,
"status": "summarizing",
"transcriptPath": "/Users/.../Library/Group Containers/group.com.privycloudless.privyecho/CLITranscriptions/audio_2026-03-18T07-00-00Z.txt",
"summaryPath": null,
"errorCode": null,
"errorDetail": null,
"workerId": "pid-12345",
"createdAt": "2026-03-18T07:00:00Z",
"updatedAt": "2026-03-18T07:02:10Z",
"startedAt": "2026-03-18T07:00:02Z",
"finishedAt": null
}
StatusMeaningqueuedTask is persisted and waiting for a worker.runningTranscription is in progress.summarizingTranscript is written; AI summary is still running.succeededTask completed successfully.failedTask failed. Check errorCode / errorDetail.cancelledReserved for future use.
stderr: Error: TASK_NOT_FOUND1These codes may appear in task status JSON:
CodeMeaningINVALID_ARGSMissing required arguments or invalid usage.AUDIO_NOT_FOUNDAudio file does not exist.AUDIO_UNREADABLEAudio file cannot be opened.NOT_LOGGED_INUser is not logged in to Geode.INSUFFICIENT_QUOTANot enough transcription quota.EMPTY_RESULTTranscription returned no text.OUTPUT_DIR_CREATE_FAILEDFailed to create the output directory.OUTPUT_WRITE_FAILEDFailed to write an output file.TRANSCRIPTION_FAILEDInternal transcription failure.SUMMARY_NOT_LOGGED_INUser is not logged in for AI summary.SUMMARY_INSUFFICIENT_QUOTANot enough AI summary quota.SUMMARY_FAILEDAI summary generation failed.WORKER_INTERRUPTEDThe worker stopped before finishing the task.
When the user wants to transcribe an audio file and later retrieve the result:
Copy the source audio into:
~/Library/Group Containers/group.com.privycloudless.privyecho/CLIInbox/
Call:
/Applications/Geode.app/Contents/Helpers/GeodeCLI --enqueue-transcription --audio "P" --language <lang> [--format ...] [--summary]
Read TASK_ID=<uuid> from stdout.
Poll:
/Applications/Geode.app/Contents/Helpers/GeodeCLI --task-status <uuid>
When status becomes succeeded:
transcriptPathsummaryPathWhen status becomes failed:
errorCode for branching logicerrorDetail for logs or user-facing contextRecommended polling behavior:
succeeded, failed, or cancelledGeodeCLI inside Geode.app for async submission and status polling.GeodeCLI returns TASK_ID=<uuid> immediately.Geode.app performs the actual transcription in --worker mode.--enqueue-transcription to submit a task.TASK_ID immediately after submission.--task-status <TASK_ID>.If the task is still in queued, running, or summarizing:
When status is succeeded:
transcriptPath.summaryPath if available.When status is failed:
errorCode.errorDetail if available.