feishu-codex-connector 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,691 @@
1
+ # Feishu Codex Connector Architecture
2
+
3
+ ## 1. Objective
4
+
5
+ `feishu-codex-connector` lets authorized Feishu/Lark users control Codex from chat, topic groups, cards, and supported document comments. Feishu/Lark is the collaboration surface. Codex is the coding agent. The connector provides the policy, orchestration, state, rendering, and safety layer between them.
6
+
7
+ The first version should provide a complete Codex-only connector:
8
+
9
+ - Receive Feishu/Lark IM and document-comment events.
10
+ - Normalize chat, topic, card, and comment contexts into stable run scopes.
11
+ - Run Codex in a selected workspace with explicit sandbox policy.
12
+ - Stream text, tool activity, status, and terminal states back through rich Feishu/Lark cards by default.
13
+ - Support session continuity, workspace switching, stop/resume, attachments, access control, diagnostics, and daemonized operation.
14
+ - Support Codex API key authentication as a first-class profile mode.
15
+ - Expose profile-local Feishu/Lark CLI identity to Codex when configured.
16
+
17
+ ## 2. Design Principles
18
+
19
+ 1. Feishu/Lark is a control surface, not the execution environment.
20
+ 2. V1 is optimized for personal local runtime. Managed team and container runtimes are future modes.
21
+ 3. Every run has a policy decision before it starts.
22
+ 4. Every conversation scope has isolated workspace, queue, active run, and Codex thread state.
23
+ 5. The bridge owns all Feishu/Lark card callbacks and verifies them before any action.
24
+ 6. Codex is accessed through a runner interface, so the product can start with the TypeScript SDK and reserve app-server features.
25
+ 7. Defaults must be safe for team use: no broad workspace, no global full access, no unauthenticated card callbacks.
26
+ 8. Profile secrets, including Codex API keys, are injected only into the intended child runtime and are never logged.
27
+
28
+ ## 3. Recommended Technology Stack
29
+
30
+ | Layer | Choice | Reason |
31
+ |---|---|---|
32
+ | Runtime | Node.js 20+ / TypeScript | Fits Feishu/Lark SDK, Codex TypeScript SDK, async streams, and JSON card rendering. |
33
+ | Feishu/Lark ingress | Feishu/Lark Channel SDK over long connection | Avoids public callback URL for local runners and simplifies event normalization. |
34
+ | Codex primary backend | `@openai/codex-sdk` | Best default for server-side programmatic Codex control. |
35
+ | Codex auth | API key plus isolated Codex home/user-login modes | V1 must support API key login while still allowing local personal Codex auth. |
36
+ | Codex advanced backend | `codex app-server` over stdio or Unix socket | Architecture-reserved for approval lifecycle, richer thread control, fork/archive, and turn steering. |
37
+ | Feishu/Lark CLI identity | Profile-local CLI config directory | Lets Codex operate Feishu/Lark resources with the intended bot or user identity. |
38
+ | Local state | JSON files with atomic writes for V1 | Simple, inspectable, easy to migrate. |
39
+ | Secret storage | Local encrypted keystore plus env/file/exec references | Keeps app secrets out of ordinary config files. |
40
+ | Service management | launchd, systemd user service, Windows Task Scheduler | Reliable local daemon behavior across major platforms. |
41
+
42
+ ## 4. System Overview
43
+
44
+ ```mermaid
45
+ flowchart LR
46
+ F["Feishu/Lark\nIM, Topic, Card, Comment"] --> I["Channel Gateway"]
47
+ I --> N["Normalizer\nBridgeMessage / BridgeAction"]
48
+ N --> A["Access & Policy Engine"]
49
+ A --> CMD["Command Router"]
50
+ A --> Q["Run Orchestrator\nQueue, Scope, Active Run"]
51
+ CMD --> C["Card & Message Renderer"]
52
+ Q --> P["Prompt Builder"]
53
+ P --> R["CodexRunner Interface"]
54
+ R --> SDK["Codex SDK Runner\nDefault"]
55
+ R --> APP["App-server Runner\nAdvanced"]
56
+ SDK --> W["Workspace Runtime"]
57
+ APP --> W
58
+ W --> R
59
+ R --> EV["Event Translator"]
60
+ EV --> C
61
+ C --> F
62
+ Q --> ST["Session / Workspace / Registry Stores"]
63
+ CMD --> ST
64
+ ```
65
+
66
+ ## 5. Core Components
67
+
68
+ ### 5.1 Channel Gateway
69
+
70
+ Responsibilities:
71
+
72
+ - Connect to Feishu or Lark using app credentials.
73
+ - Receive IM messages, card actions, document-comment events, reconnect signals, and SDK errors.
74
+ - Send replies as streaming cards, streaming markdown, plain markdown, or document-comment replies.
75
+ - Apply output throttling to avoid platform rate limits.
76
+ - Keep raw event payloads where normalized events omit important data, such as form values or sender type.
77
+
78
+ Non-goals:
79
+
80
+ - It must not execute Codex.
81
+ - It must not decide workspace or sandbox policy.
82
+
83
+ ### 5.2 Event Normalizer
84
+
85
+ Converts platform-specific events into internal objects:
86
+
87
+ ```ts
88
+ type BridgeSource = "im" | "card" | "comment";
89
+
90
+ interface BridgeMessage {
91
+ source: BridgeSource;
92
+ scopeId: string;
93
+ chatId?: string;
94
+ threadId?: string;
95
+ commentScopeId?: string;
96
+ messageId: string;
97
+ actorId: string;
98
+ actorName?: string;
99
+ actorType?: "user" | "bot";
100
+ text: string;
101
+ mentions: BridgeMention[];
102
+ resources: BridgeResource[];
103
+ raw: unknown;
104
+ }
105
+ ```
106
+
107
+ Scope rules:
108
+
109
+ | Feishu/Lark context | Scope ID |
110
+ |---|---|
111
+ | Private chat | `chat:<chatId>` |
112
+ | Normal group | `chat:<chatId>` |
113
+ | Topic group | `topic:<chatId>:<threadId>` |
114
+ | Card callback | Same as card carrier message scope |
115
+ | Document comment execution | `comment:<fileTokenHash>:<commentIdHash>:<nonce>` |
116
+ | Document-level Codex continuity | `doc:<fileTokenHash>` |
117
+
118
+ ### 5.3 Access & Policy Engine
119
+
120
+ Responsibilities:
121
+
122
+ - Check whether the actor can use the bot in a private chat.
123
+ - Check whether the group is allowed and whether mention is required.
124
+ - Check whether the actor can run admin commands.
125
+ - Resolve and validate the requested working directory.
126
+ - Decide runtime access mode and Codex sandbox.
127
+ - Validate attachments and resource bindings.
128
+ - Generate a policy fingerprint used for safe thread resume and card callback verification.
129
+
130
+ Access modes:
131
+
132
+ | Bridge access | Codex sandbox | Default use |
133
+ |---|---|---|
134
+ | `read-only` | `read-only` | Review, explain, summarize. |
135
+ | `workspace` | `workspace-write` | Default coding work. |
136
+ | `full` | `danger-full-access` | Owner-only or isolated runner. |
137
+
138
+ Default profile policy:
139
+
140
+ ```json
141
+ {
142
+ "permissions": {
143
+ "defaultAccess": "workspace",
144
+ "maxAccess": "workspace"
145
+ },
146
+ "networkAccess": false
147
+ }
148
+ ```
149
+
150
+ The policy fingerprint should include at least:
151
+
152
+ ```text
153
+ scopeId
154
+ cwdRealpath
155
+ sandbox
156
+ networkAccess
157
+ access policy digest
158
+ resource scope digest
159
+ attachment policy digest
160
+ codex auth mode
161
+ codexHome or runtime identity
162
+ Feishu/Lark CLI identity preset and config digest
163
+ ```
164
+
165
+ ### 5.4 Command Router
166
+
167
+ Built-in commands must run before ordinary messages enter the Codex queue.
168
+
169
+ Command classes:
170
+
171
+ - Session: `/new`, `/reset`, `/resume`
172
+ - Workspace: `/cd`, `/ws`
173
+ - Run control: `/stop`, `/timeout`
174
+ - Status and diagnostics: `/status`, `/doctor`, `/help`
175
+ - Access control: `/invite`, `/remove`
176
+ - Runtime: `/ps`, `/exit`, `/reconnect`
177
+ - Configuration: `/config`
178
+
179
+ Admin-gated commands:
180
+
181
+ ```text
182
+ /cd
183
+ /ws
184
+ /config
185
+ /invite
186
+ /remove
187
+ /doctor
188
+ /ps
189
+ /exit
190
+ /reconnect
191
+ ```
192
+
193
+ `/stop` without an explicit target is allowed for the current scope. Stopping another scope is admin-only.
194
+
195
+ ### 5.5 Run Orchestrator
196
+
197
+ Responsibilities:
198
+
199
+ - Maintain one active run per scope.
200
+ - Debounce multiple messages in a short quiet window.
201
+ - Block a scope queue while a run is active.
202
+ - Accumulate messages received during a run and flush them into the next run.
203
+ - Enforce global process concurrency.
204
+ - Submit runs to a `CodexRunner`.
205
+ - Stop runs on `/stop`, reconnect, shutdown, or idle timeout.
206
+ - Persist session state after Codex emits a thread ID.
207
+
208
+ Queue model:
209
+
210
+ ```mermaid
211
+ stateDiagram-v2
212
+ [*] --> Idle
213
+ Idle --> Debouncing: message
214
+ Debouncing --> Running: quiet window elapsed
215
+ Debouncing --> Debouncing: more messages
216
+ Running --> QueuedDuringRun: message
217
+ QueuedDuringRun --> QueuedDuringRun: more messages
218
+ Running --> Idle: run terminal and no queued messages
219
+ QueuedDuringRun --> Debouncing: run terminal
220
+ Running --> Idle: stop/new/cd
221
+ ```
222
+
223
+ ### 5.6 Prompt Builder
224
+
225
+ Prompt input is structured rather than free-form concatenation.
226
+
227
+ ```xml
228
+ <bridge_context>
229
+ {"source":"im","scopeId":"topic:...","chatId":"...","actorId":"...","botOpenId":"..."}
230
+ </bridge_context>
231
+
232
+ <quoted_messages>
233
+ [...]
234
+ </quoted_messages>
235
+
236
+ <interactive_cards>
237
+ [...]
238
+ </interactive_cards>
239
+
240
+ <attachments>
241
+ [{"kind":"image","path":"/local/cache/x.png","hash":"..."}]
242
+ </attachments>
243
+
244
+ <user_input>
245
+ User text
246
+ </user_input>
247
+ ```
248
+
249
+ Bridge instructions should tell Codex:
250
+
251
+ - It is running inside a Feishu/Lark bridge.
252
+ - Bridge metadata is not user-visible and should not be repeated.
253
+ - It must respect the provided workspace and runtime policy.
254
+ - It should not read bridge secret files.
255
+ - It should use profile-bound Feishu/Lark CLI environment only when available.
256
+ - It must not bypass bridge environment variables or switch to unrelated local app credentials.
257
+
258
+ ### 5.7 Codex Runner Interface
259
+
260
+ The bridge must not depend directly on one Codex transport.
261
+
262
+ ```ts
263
+ interface CodexRunner {
264
+ start(input: CodexRunInput): Promise<CodexRunHandle>;
265
+ resume(threadId: string, input: CodexRunInput): Promise<CodexRunHandle>;
266
+ listThreads(input: CodexThreadListInput): Promise<CodexThreadSummary[]>;
267
+ stop(runId: string): Promise<void>;
268
+ checkAvailability(): Promise<RunnerAvailability>;
269
+ }
270
+
271
+ interface CodexRunHandle {
272
+ runId: string;
273
+ threadId?: string;
274
+ events: AsyncIterable<CodexBridgeEvent>;
275
+ stop(): Promise<void>;
276
+ }
277
+ ```
278
+
279
+ #### Default: Codex SDK Runner
280
+
281
+ Used for V1 normal execution.
282
+
283
+ Expected capabilities:
284
+
285
+ - Start a new thread.
286
+ - Resume a thread.
287
+ - Stream run events.
288
+ - Pass working directory, sandbox, images, and environment.
289
+ - Stop using `AbortSignal`, followed by process-level fallback if needed.
290
+
291
+ #### Advanced: App-server Runner
292
+
293
+ Reserved for V2 or later profiles that require advanced Codex lifecycle control. It is not part of the V1 execution path.
294
+
295
+ Expected capabilities:
296
+
297
+ - `thread/start`, `thread/resume`, `thread/list`, `thread/archive`
298
+ - `turn/start`, `turn/interrupt`, `turn/steer`
299
+ - approval request/decision mapping to Feishu/Lark cards
300
+ - schema generation and version pinning
301
+
302
+ Transport policy:
303
+
304
+ - Prefer stdio for local child process mode.
305
+ - Use Unix socket for local multi-client mode.
306
+ - Do not expose app-server WebSocket over non-loopback network in V1.
307
+
308
+ ### 5.8 Event Translator
309
+
310
+ Codex events are translated to bridge events:
311
+
312
+ ```ts
313
+ type CodexBridgeEvent =
314
+ | { type: "thread"; threadId: string }
315
+ | { type: "text"; delta: string }
316
+ | { type: "tool_start"; id: string; name: string; input: unknown }
317
+ | { type: "tool_end"; id: string; output: string; isError: boolean }
318
+ | { type: "usage"; inputTokens?: number; outputTokens?: number }
319
+ | { type: "approval_request"; request: ApprovalRequest }
320
+ | { type: "done"; reason: "normal" | "interrupted" | "timeout" }
321
+ | { type: "error"; message: string };
322
+ ```
323
+
324
+ `approval_request` is reserved for the app-server runner. The SDK runner may not emit it in V1.
325
+
326
+ ### 5.9 Card & Message Renderer
327
+
328
+ Reply modes:
329
+
330
+ | Mode | Use |
331
+ |---|---|
332
+ | `card` | V1 default. Rich run state, tool panels, stop button, footer. |
333
+ | `markdown` | Fallback when card creation or update fails. |
334
+ | `text` | One final message after completion. |
335
+ | `comment` | Plain-text document comment reply. |
336
+
337
+ The renderer maintains a `RunState`:
338
+
339
+ - text blocks
340
+ - tool blocks
341
+ - current footer
342
+ - terminal state
343
+ - interrupt/error/timeout markers
344
+ - optional usage summary
345
+
346
+ Card callbacks must be signed.
347
+
348
+ Callback token fields:
349
+
350
+ ```text
351
+ runId
352
+ scopeId
353
+ chatId
354
+ operatorOpenId
355
+ action
356
+ policyFingerprint
357
+ expiresAt
358
+ nonce
359
+ keyVersion
360
+ ```
361
+
362
+ ### 5.10 Session Catalog
363
+
364
+ Use a catalog instead of a simple chat-to-thread map.
365
+
366
+ ```ts
367
+ interface SessionCatalogEntry {
368
+ key: string;
369
+ scopeId: string;
370
+ cwdRealpath: string;
371
+ policyFingerprint: string;
372
+ codexThreadId: string;
373
+ status: "active" | "archived";
374
+ updatedAt: number;
375
+ summary?: string;
376
+ }
377
+ ```
378
+
379
+ Catalog key:
380
+
381
+ ```text
382
+ scopeId + cwdRealpath + policyFingerprint
383
+ ```
384
+
385
+ This prevents unsafe resume after workspace, sandbox, access, or runtime changes.
386
+
387
+ ### 5.11 Workspace Store
388
+
389
+ Tracks current and named workspaces.
390
+
391
+ ```ts
392
+ interface WorkspaceStore {
393
+ currentByScope: Record<string, string>;
394
+ aliases: Record<string, string>;
395
+ }
396
+ ```
397
+
398
+ Workspace validation must reject broad directories:
399
+
400
+ - filesystem root
401
+ - home root
402
+ - user root
403
+ - Desktop and Downloads as root workspace
404
+ - system roots
405
+ - temp root
406
+ - volume root
407
+
408
+ ### 5.12 Media Store
409
+
410
+ Responsibilities:
411
+
412
+ - Download Feishu/Lark message resources by message ID and file key.
413
+ - Store files by content hash.
414
+ - Normalize MIME and extension.
415
+ - Apply max count, max file size, total run size, and image MIME policies.
416
+ - Remove rejected files.
417
+ - Garbage-collect old cache entries.
418
+
419
+ Images are passed to Codex. Unsupported files remain in prompt context as rejected/skipped attachments.
420
+
421
+ ### 5.13 Document Comment Handler
422
+
423
+ Responsibilities:
424
+
425
+ - React only when the bot is mentioned in supported comments.
426
+ - Fetch comment question, quote, target document, and thread metadata.
427
+ - Build a comment-specific prompt.
428
+ - Run Codex without streaming UI.
429
+ - Post a plain-text reply in the same comment thread.
430
+ - Maintain document-level Codex continuity.
431
+ - Avoid replying to the bridge's own comments.
432
+
433
+ Comment replies should avoid Markdown because document comments often show raw formatting symbols.
434
+
435
+ ### 5.14 Profile Runtime
436
+
437
+ Each profile has isolated:
438
+
439
+ - Feishu/Lark app credentials
440
+ - Codex runtime configuration and auth mode
441
+ - local state and logs
442
+ - media cache
443
+ - session catalog
444
+ - workspace store
445
+ - Feishu/Lark CLI config exposed to Codex when enabled
446
+
447
+ Profile config sketch:
448
+
449
+ ```json
450
+ {
451
+ "schemaVersion": 1,
452
+ "activeProfile": "default",
453
+ "profiles": {
454
+ "default": {
455
+ "tenant": "feishu",
456
+ "app": {
457
+ "id": "cli_xxx",
458
+ "secret": { "source": "keystore", "id": "app-cli_xxx" }
459
+ },
460
+ "codex": {
461
+ "backend": "sdk",
462
+ "auth": {
463
+ "mode": "api-key",
464
+ "apiKey": { "source": "keystore", "id": "openai-api-key-default" }
465
+ },
466
+ "codexHome": "~/.feishu-codex/profiles/default/codex-home",
467
+ "inheritUserCodexHome": false
468
+ },
469
+ "feishuCli": {
470
+ "enabled": true,
471
+ "identityPreset": "bot-only",
472
+ "configDir": "~/.feishu-codex/profiles/default/feishu-cli"
473
+ },
474
+ "permissions": {
475
+ "defaultAccess": "workspace",
476
+ "maxAccess": "workspace",
477
+ "networkAccess": false
478
+ },
479
+ "access": {
480
+ "allowedUsers": [],
481
+ "allowedChats": [],
482
+ "admins": [],
483
+ "requireMentionInGroup": true
484
+ }
485
+ }
486
+ }
487
+ }
488
+ ```
489
+
490
+ #### Codex Authentication Modes
491
+
492
+ | Mode | V1 status | Behavior |
493
+ |---|---|---|
494
+ | `api-key` | Required | Read a profile secret and pass it to the Codex SDK as the run API key. The key must not be exported to bridge-wide process env. |
495
+ | `codex-home` | Required | Use an isolated profile Codex home for local Codex login state and config. |
496
+ | `inherit-user` | Optional | Reuse the operator machine's existing Codex login only when explicitly enabled. This is convenient for personal mode but weaker for reproducibility. |
497
+
498
+ API key mode is the most predictable for Feishu remote operation because the local daemon can run Codex even if no interactive Codex login exists on the host. The bridge must support secret rotation by changing the secret reference without rewriting historical logs or sessions.
499
+
500
+ #### Feishu/Lark CLI Identity
501
+
502
+ V1 implements profile-local Feishu/Lark CLI identity projection. When enabled, the bridge prepares a CLI config directory under the profile and injects only the required environment variables into Codex runs.
503
+
504
+ Identity presets:
505
+
506
+ | Preset | V1 status | Behavior |
507
+ |---|---|---|
508
+ | `bot-only` | Required default | Codex can use Feishu/Lark CLI capabilities that operate as the configured bot/app. |
509
+ | `user-default` | Required for personal mode | Codex can use the local user's CLI OAuth identity when explicitly configured. |
510
+ | `disabled` | Required | No Feishu/Lark CLI identity is exposed to Codex. |
511
+
512
+ Safety rules:
513
+
514
+ - The bridge must never expose host-global Feishu/Lark CLI config unless a profile explicitly opts into `user-default`.
515
+ - Group chats should default to `bot-only` unless the owner explicitly permits user identity projection.
516
+ - `/status` and `/doctor` show identity preset and config health, but never tokens.
517
+ - Policy fingerprint includes CLI identity preset and profile CLI config digest.
518
+
519
+ ### 5.15 Runtime Registry and Locks
520
+
521
+ The bridge should prevent accidental duplicate listeners.
522
+
523
+ Locks:
524
+
525
+ - profile lock: one process per profile
526
+ - app lock: one process per Feishu/Lark app ID
527
+
528
+ Registry:
529
+
530
+ - process short ID
531
+ - PID
532
+ - profile
533
+ - tenant
534
+ - app ID
535
+ - bot name
536
+ - started time
537
+ - log paths
538
+
539
+ ### 5.16 Observability
540
+
541
+ Required logs:
542
+
543
+ - structured JSONL logs
544
+ - startup/preflight
545
+ - event intake
546
+ - access decisions
547
+ - command dispatch
548
+ - run lifecycle
549
+ - Codex event transitions
550
+ - queue and pool state
551
+ - card callback verification
552
+ - Feishu/Lark API failures
553
+ - workspace and attachment policy decisions
554
+
555
+ Metrics hooks:
556
+
557
+ - run duration
558
+ - active runs
559
+ - queue wait
560
+ - tokens
561
+ - failures by phase
562
+ - reconnect count
563
+ - callback denials
564
+
565
+ Telemetry is opt-in only.
566
+
567
+ ## 6. Approval Mapping Architecture
568
+
569
+ V1 does not implement Codex runtime approval mapping. It uses explicit sandbox policy and non-interactive execution behavior. The architecture reserves the event type and Feishu/Lark card flow for the app-server runner in V2.
570
+
571
+ ```mermaid
572
+ sequenceDiagram
573
+ participant C as Codex App-server
574
+ participant B as Bridge
575
+ participant F as Feishu/Lark Card
576
+ participant U as Authorized User
577
+
578
+ C->>B: approval_request
579
+ B->>B: Build approval policy context
580
+ B->>F: Send signed Approve/Deny card
581
+ U->>F: Click Approve or Deny
582
+ F->>B: card_action
583
+ B->>B: Verify signature, nonce, actor, scope, policy
584
+ B->>C: approval_decision
585
+ C->>B: Continue or fail turn
586
+ B->>F: Update run card
587
+ ```
588
+
589
+ Approval cards must show:
590
+
591
+ - requested action
592
+ - command or tool name
593
+ - cwd
594
+ - sandbox
595
+ - network request if present
596
+ - risk summary
597
+ - requesting run and actor
598
+
599
+ Only owner/admin or the original authorized actor may approve, depending on profile policy.
600
+
601
+ ## 7. Deployment Modes
602
+
603
+ ### 7.1 Personal Local Mode
604
+
605
+ - Runs on the user's workstation.
606
+ - Uses one Feishu/Lark app.
607
+ - Owner-only by default.
608
+ - Primary V1 runtime mode.
609
+ - Supports Codex API key auth, isolated Codex home, or explicit user Codex auth inheritance.
610
+ - Supports profile-local Feishu/Lark CLI identity projection.
611
+ - Suitable for direct workspace editing.
612
+
613
+ ### 7.2 Team Managed Mode
614
+
615
+ - Future mode after V1.
616
+ - Runs on a controlled host.
617
+ - Uses per-project profiles.
618
+ - Uses isolated Codex home.
619
+ - Uses git worktrees or containers.
620
+ - Produces patch or PR output instead of editing shared branches directly.
621
+ - Requires audit logs and tighter access policy.
622
+
623
+ ### 7.3 Container Runner Mode
624
+
625
+ - Future mode after V1.
626
+ - Each run gets an isolated workspace.
627
+ - Secrets are short-lived.
628
+ - Full access may be allowed inside the container only.
629
+ - Final artifact is diff, patch, PR, or uploaded report.
630
+
631
+ ## 8. Failure Handling
632
+
633
+ | Failure | Handling |
634
+ |---|---|
635
+ | Feishu/Lark reconnect loop | Log, surface `/status`, keep retrying, allow `/reconnect`. |
636
+ | Codex binary or SDK unavailable | Preflight failure with actionable diagnostic. |
637
+ | Workspace invalid | Reject before run and explain. |
638
+ | Queue full or pool full | Defer or return busy message depending on source. |
639
+ | Stream renderer failure | Fall back to final markdown/text reply. |
640
+ | Card callback auth failure | Deny silently or log low-detail denial. |
641
+ | Idle run | Stop Codex, mark timeout in card. |
642
+ | Shutdown | Stop active runs, flush stores, disconnect channel. |
643
+
644
+ ## 9. Milestones
645
+
646
+ ### V1: Codex-only Bridge
647
+
648
+ - Feishu/Lark long-connection channel.
649
+ - Codex SDK runner.
650
+ - Codex API key authentication with profile-scoped secret references.
651
+ - Isolated profile Codex home, with explicit personal user-auth inheritance only when configured.
652
+ - Profile-local Feishu/Lark CLI identity projection with `bot-only`, `user-default`, and `disabled` presets.
653
+ - IM private/group/topic support.
654
+ - Rich CardKit run cards as the default reply surface.
655
+ - Signed card callbacks with stop button.
656
+ - Markdown/text fallback when card delivery fails.
657
+ - `/new`, `/cd`, `/ws`, `/resume`, `/status`, `/stop`, `/timeout`, `/help`.
658
+ - Interactive `/config` and status cards for core runtime settings.
659
+ - Owner/admin/user/group access control.
660
+ - Per-scope queue, debounce, active run tracking.
661
+ - Workspace validation.
662
+ - Session catalog.
663
+ - Basic media image support.
664
+ - Document comment handling with plain-text replies.
665
+ - Profile config and local state.
666
+ - Foreground run and daemon start/stop/status.
667
+ - Structured logs and `/doctor`.
668
+
669
+ ### V1.5: Complete Collaboration Surface
670
+
671
+ - Multi-profile service management.
672
+ - Richer CardKit layouts and card template versioning.
673
+ - More Feishu/Lark resource helpers behind the profile CLI identity.
674
+ - Additional attachment types and document context expansion.
675
+ - Packaging polish and migration helpers.
676
+
677
+ ### V2: Advanced Codex Control
678
+
679
+ - App-server runner.
680
+ - Approval mapping to Feishu/Lark cards.
681
+ - Thread list/fork/archive.
682
+ - Turn steer.
683
+ - Worktree/container runner.
684
+ - PR creation and diff review workflows.
685
+
686
+ ## 10. References
687
+
688
+ - Codex SDK: `https://developers.openai.com/codex/sdk`
689
+ - Codex app-server: `https://developers.openai.com/codex/app-server`
690
+ - Codex sandboxing and approvals: `https://developers.openai.com/codex/concepts/sandboxing`
691
+ - Feishu/Lark Channel SDK and long-connection event delivery: Feishu/Lark Open Platform documentation