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.
package/docs/SPEC.md ADDED
@@ -0,0 +1,825 @@
1
+ # Feishu Codex Connector Functional Specification
2
+
3
+ ## 1. Scope
4
+
5
+ This specification defines the first implementation target for `feishu-codex-connector`: a Codex-only connector controlled from Feishu/Lark.
6
+
7
+ The first version must feel complete for a single owner, a small team, and a project group:
8
+
9
+ - Start and manage the bridge locally or as a background service.
10
+ - Bind a Feishu/Lark app.
11
+ - Receive private, group, topic, card, and document-comment inputs.
12
+ - Run Codex in a selected workspace.
13
+ - Stream output back to the user through rich run cards by default.
14
+ - Preserve session continuity.
15
+ - Enforce access, workspace, sandbox, callback, and attachment policies.
16
+ - Support Codex API key authentication without requiring interactive Codex login on the host.
17
+ - Expose profile-local Feishu/Lark CLI identity to Codex when configured.
18
+
19
+ ## 2. Product Personas
20
+
21
+ ### 2.1 Owner
22
+
23
+ The person who creates or owns the Feishu/Lark app. The owner can:
24
+
25
+ - Use the bot in private chats and groups.
26
+ - Manage access lists.
27
+ - Change configuration.
28
+ - Run diagnostics.
29
+ - Stop or restart connector processes.
30
+
31
+ ### 2.2 Admin
32
+
33
+ A trusted maintainer added by the owner. An admin can:
34
+
35
+ - Use private chat.
36
+ - Use the bot in any group where access policy permits admin bypass.
37
+ - Manage workspaces and access.
38
+ - Run diagnostics and lifecycle commands.
39
+
40
+ ### 2.3 Allowed User
41
+
42
+ A user explicitly allowed to use the bot in private chat or in an allowed group. An allowed user can:
43
+
44
+ - Send ordinary Codex tasks.
45
+ - Stop their current run.
46
+ - Reset or resume their own scope.
47
+
48
+ ### 2.4 Group Member
49
+
50
+ A member of an allowed group. They can use the bot only according to group mention policy.
51
+
52
+ ## 3. Profile and Runtime Management
53
+
54
+ ### V1 Runtime Boundary
55
+
56
+ V1 primary mode is personal local mode.
57
+
58
+ Required behavior:
59
+
60
+ - The bridge runs on the owner's workstation or personal development host.
61
+ - Codex edits the selected local workspace directly under the configured sandbox.
62
+ - Owner-only usage is the safest default, while allowed users/groups are opt-in.
63
+ - Team-managed worktrees, containers, PR automation, and remote multi-tenant hosting are future modes.
64
+ - App-server execution is not required for V1, but the runner interface must not block adding it later.
65
+
66
+ ### 3.1 Profile Create
67
+
68
+ Command:
69
+
70
+ ```bash
71
+ feishu-codex profile create <name>
72
+ ```
73
+
74
+ Required behavior:
75
+
76
+ - Prompt for tenant: `feishu` or `lark`.
77
+ - Prompt for app ID and app secret, or run an app-binding wizard if available.
78
+ - Detect Codex SDK/runtime availability.
79
+ - Prompt for Codex auth mode: `api-key`, `codex-home`, or `inherit-user`.
80
+ - For `api-key`, store the API key as a secret reference and validate it with a low-risk availability check.
81
+ - Create a profile-local Codex home unless `inherit-user` is explicitly selected.
82
+ - Initialize profile-local Feishu/Lark CLI identity settings with `bot-only` as the default.
83
+ - Create profile directory under `~/.feishu-codex/profiles/<name>`.
84
+ - Create local state files with secure permissions.
85
+ - Store app secret using configured secret storage.
86
+ - Optionally set an initial workspace.
87
+
88
+ Acceptance criteria:
89
+
90
+ - New profile appears in `profile list`.
91
+ - App secret is not written as cleartext in normal config.
92
+ - Codex API key is not written as cleartext in normal config.
93
+ - `feishu-codex run --profile <name>` can start from the profile.
94
+
95
+ ### 3.2 Profile Use/List/Remove/Export
96
+
97
+ Commands:
98
+
99
+ ```bash
100
+ feishu-codex profile list
101
+ feishu-codex profile use <name>
102
+ feishu-codex profile remove <name>
103
+ feishu-codex profile export <name>
104
+ ```
105
+
106
+ Required behavior:
107
+
108
+ - `list` shows active profile, tenant, app ID suffix, workspace status, backend, Codex auth mode, and Feishu/Lark CLI identity preset.
109
+ - `use` changes default profile.
110
+ - `remove` archives local state by default.
111
+ - `remove --purge --yes` permanently deletes profile state.
112
+ - `export` redacts secrets unless `--include-secrets --yes` is provided.
113
+
114
+ ### 3.3 Foreground Run
115
+
116
+ Command:
117
+
118
+ ```bash
119
+ feishu-codex run [--profile <name>] [--workspace <path>]
120
+ ```
121
+
122
+ Required behavior:
123
+
124
+ - Resolve profile.
125
+ - Run preflight checks.
126
+ - Acquire profile and app locks.
127
+ - Connect Feishu/Lark channel.
128
+ - Register process.
129
+ - Listen until signal or `/exit`.
130
+ - Flush stores on shutdown.
131
+
132
+ ### 3.4 Background Service
133
+
134
+ Commands:
135
+
136
+ ```bash
137
+ feishu-codex start [--profile <name>]
138
+ feishu-codex stop [--profile <name>]
139
+ feishu-codex restart [--profile <name>]
140
+ feishu-codex status [--profile <name>]
141
+ feishu-codex unregister [--profile <name>]
142
+ ```
143
+
144
+ Required behavior:
145
+
146
+ - macOS: launchd user agent.
147
+ - Linux: systemd user service.
148
+ - Windows: Task Scheduler task.
149
+ - Logs written under profile logs directory.
150
+ - Service commands must not depend on temporary `npx` paths.
151
+
152
+ ## 4. Feishu/Lark Event Handling
153
+
154
+ ### 4.1 Private Message
155
+
156
+ Required behavior:
157
+
158
+ - Accept message when actor is owner, admin, or allowed user.
159
+ - Do not require bot mention.
160
+ - Scope ID is private chat scope.
161
+ - Ordinary messages enter the run queue.
162
+ - Slash commands are handled immediately.
163
+
164
+ Acceptance criteria:
165
+
166
+ - Unauthorized private sender gets no Codex run.
167
+ - Authorized sender receives a streamed response.
168
+
169
+ ### 4.2 Group Message
170
+
171
+ Required behavior:
172
+
173
+ - Accept message when group is allowed, or actor is owner/admin.
174
+ - If `requireMentionInGroup` is true, ignore messages without a real bot mention.
175
+ - Ignore mention-all as a trigger.
176
+ - Scope ID is group chat scope.
177
+
178
+ Acceptance criteria:
179
+
180
+ - Allowed group + real mention triggers run.
181
+ - Allowed group + no mention does not trigger run when mention is required.
182
+ - Disallowed group does not run Codex.
183
+
184
+ ### 4.3 Topic Group Message
185
+
186
+ Required behavior:
187
+
188
+ - Resolve topic/thread ID.
189
+ - Scope ID includes chat ID and topic/thread ID.
190
+ - Replies are posted back into the same topic when possible.
191
+ - Each topic has independent workspace, queue, active run, and session state.
192
+
193
+ ### 4.4 Quoted Message Context
194
+
195
+ Required behavior:
196
+
197
+ - Detect when a message quotes another message.
198
+ - Fetch quoted message content when permitted.
199
+ - Deduplicate quote targets across a batched run.
200
+ - Include quote context in structured prompt.
201
+ - Avoid fetching quote targets that are already part of the current batch.
202
+
203
+ ### 4.5 Card Action
204
+
205
+ Required behavior:
206
+
207
+ - Resolve card action scope.
208
+ - Verify actor access before executing.
209
+ - Dispatch built-in command callbacks.
210
+ - Forward signed agent callbacks into the scope queue as synthetic messages.
211
+ - Include CardKit form values when present.
212
+ - Reject unsigned sensitive callbacks.
213
+
214
+ Acceptance criteria:
215
+
216
+ - Stop button stops only the matching active run.
217
+ - Replay of the same callback nonce is rejected.
218
+ - Callback from a different operator is rejected.
219
+
220
+ ### 4.6 Document Comment Mention
221
+
222
+ Required behavior:
223
+
224
+ - React only when the bot is mentioned.
225
+ - Support configured document/file types for comment retrieval.
226
+ - Fetch comment text, quote, and context.
227
+ - Build a comment-specific prompt.
228
+ - Run Codex using document-level session continuity.
229
+ - Post plain-text reply into the same comment thread.
230
+ - Skip self-replies.
231
+
232
+ Acceptance criteria:
233
+
234
+ - Mention in supported comment triggers one reply.
235
+ - Reply does not contain raw Markdown formatting unless user explicitly requested literal Markdown.
236
+ - Concurrent comments on the same document do not corrupt the document-level session.
237
+
238
+ ## 5. Built-in Commands
239
+
240
+ ### 5.1 `/help`
241
+
242
+ Shows available commands and current agent/backend label.
243
+
244
+ ### 5.2 `/status`
245
+
246
+ Shows:
247
+
248
+ - profile
249
+ - tenant
250
+ - bot name if known
251
+ - current scope
252
+ - chat mode
253
+ - selected workspace
254
+ - Codex backend
255
+ - Codex auth mode
256
+ - Feishu/Lark CLI identity preset
257
+ - sandbox/access mode
258
+ - current thread ID or empty state
259
+ - active run status
260
+ - queue snapshot
261
+ - access status
262
+ - owner refresh status
263
+
264
+ ### 5.3 `/new` and `/reset`
265
+
266
+ Required behavior:
267
+
268
+ - Stop current run if active.
269
+ - Archive or clear active Codex thread for the current scope.
270
+ - Preserve non-session preferences such as idle timeout if configured.
271
+
272
+ ### 5.4 `/cd <path>`
273
+
274
+ Required behavior:
275
+
276
+ - Admin-only.
277
+ - Accept absolute paths and `~/...`.
278
+ - Reject relative paths.
279
+ - Resolve realpath.
280
+ - Reject dangerous broad directories.
281
+ - Stop current run.
282
+ - Set current scope workspace.
283
+ - Reset current scope session.
284
+
285
+ ### 5.5 `/ws`
286
+
287
+ Subcommands:
288
+
289
+ ```text
290
+ /ws list
291
+ /ws save <name>
292
+ /ws add <name> <path>
293
+ /ws use <name>
294
+ /ws remove <name>
295
+ ```
296
+
297
+ Required behavior:
298
+
299
+ - Admin-only.
300
+ - Workspace aliases are scoped by profile, owner, and chat scope.
301
+ - Legacy global aliases may be read if migration support is enabled.
302
+ - `use` validates the target path before switching.
303
+ - `add` validates the target path before saving.
304
+
305
+ ### 5.5.1 `/new group`
306
+
307
+ Required behavior:
308
+
309
+ - Owner/admin-only.
310
+ - Create a new Feishu/Lark group chat.
311
+ - Invite the requesting user.
312
+ - Inherit the source scope workspace when configured.
313
+ - Send a welcome message to the new group.
314
+ - Reply to the source scope with the creation result.
315
+
316
+ ### 5.6 `/resume`
317
+
318
+ Required behavior:
319
+
320
+ - Show recent compatible Codex threads for current workspace and policy.
321
+ - In group chats, avoid exposing detailed history unless configured.
322
+ - Issue short-lived nonces for resume candidates.
323
+ - `/resume use <nonce>` restores the selected thread only if scope, cwd, and policy fingerprint match.
324
+
325
+ ### 5.7 `/stop`
326
+
327
+ Required behavior:
328
+
329
+ - Stop current scope run.
330
+ - Do not send an extra reply if the run card can update itself.
331
+ - Admins may stop another scope by explicit target.
332
+
333
+ ### 5.8 `/timeout`
334
+
335
+ Required behavior:
336
+
337
+ - Show current idle watchdog setting.
338
+ - Set per-scope timeout in minutes.
339
+ - `off` disables per-scope watchdog.
340
+ - `default` clears per-scope override.
341
+ - Clamp allowed values to a safe range.
342
+
343
+ ### 5.9 `/config`
344
+
345
+ Required behavior:
346
+
347
+ - Admin-only.
348
+ - Render interactive configuration card.
349
+ - Support reply mode, show tool calls, max concurrency, mention policy, access mode, network access, idle timeout, Codex auth mode, and Feishu/Lark CLI identity preset.
350
+ - Validate form values before saving.
351
+ - Restart or reconnect when changes require it.
352
+
353
+ ### 5.10 `/invite` and `/remove`
354
+
355
+ Required behavior:
356
+
357
+ - Admin-only.
358
+ - Add/remove allowed users, groups, and admins.
359
+ - Parse mentioned users from structured mentions.
360
+ - `/invite group` allows current group.
361
+ - `/invite all group` may add all known groups if the platform API permits.
362
+
363
+ ### 5.11 `/doctor`
364
+
365
+ Required behavior:
366
+
367
+ - Admin-only.
368
+ - Rate limited per user.
369
+ - Checks workspace, access, policy, queue, Codex availability, and echo run.
370
+ - In group chats, send sensitive diagnostic details privately to the operator.
371
+
372
+ ### 5.12 `/ps`, `/exit`, `/reconnect`
373
+
374
+ Required behavior:
375
+
376
+ - Admin-only.
377
+ - `/ps` lists registered connector processes.
378
+ - `/exit <id|#>` stops selected process.
379
+ - `/reconnect` pauses new runs, stops or waits for active runs, reloads config, reconnects channel.
380
+
381
+ ## 6. Codex Execution
382
+
383
+ ### 6.1 Backend Selection
384
+
385
+ Profile field:
386
+
387
+ ```json
388
+ {
389
+ "codex": {
390
+ "backend": "sdk"
391
+ }
392
+ }
393
+ ```
394
+
395
+ Supported values:
396
+
397
+ | Backend | V1 status | Purpose |
398
+ |---|---|---|
399
+ | `sdk` | Required | Normal execution through Codex TypeScript SDK. |
400
+ | `app-server` | Reserved | Advanced lifecycle and approval support in V2. Not used for V1 normal execution. |
401
+ | `exec-json` | Diagnostic fallback | Compatibility fallback for local troubleshooting, not the product default. |
402
+
403
+ ### 6.2 Run Input
404
+
405
+ Every Codex run receives:
406
+
407
+ - run ID
408
+ - prompt
409
+ - cwd realpath
410
+ - optional thread ID
411
+ - sandbox mode
412
+ - network access setting
413
+ - image paths
414
+ - profile environment
415
+ - Codex auth material resolved from the profile secret provider
416
+ - Feishu/Lark CLI identity environment when enabled
417
+ - stop signal
418
+ - idle timeout
419
+
420
+ ### 6.3 Run Output
421
+
422
+ Runner output must be translated into:
423
+
424
+ - thread started/resumed
425
+ - text delta or final text
426
+ - tool start
427
+ - tool result
428
+ - usage
429
+ - approval request if backend supports it
430
+ - done
431
+ - error
432
+
433
+ ### 6.4 Stop Semantics
434
+
435
+ Required behavior:
436
+
437
+ - `/stop` marks the run interrupted.
438
+ - SDK runner uses abort signal first.
439
+ - Process fallback terminates the child process tree when available.
440
+ - Stop has a grace period before force kill.
441
+ - Card terminal state becomes interrupted.
442
+
443
+ ### 6.5 Thread Continuity
444
+
445
+ Required behavior:
446
+
447
+ - Save Codex thread ID after first successful thread event.
448
+ - Resume only when scope, cwd, and policy fingerprint match.
449
+ - Reset thread on `/new`, `/cd`, or incompatible policy change.
450
+
451
+ ### 6.6 Codex Authentication
452
+
453
+ Profile field:
454
+
455
+ ```json
456
+ {
457
+ "codex": {
458
+ "backend": "sdk",
459
+ "auth": {
460
+ "mode": "api-key",
461
+ "apiKey": { "source": "keystore", "id": "openai-api-key-default" }
462
+ },
463
+ "codexHome": "~/.feishu-codex/profiles/default/codex-home",
464
+ "inheritUserCodexHome": false
465
+ }
466
+ }
467
+ ```
468
+
469
+ Supported auth modes:
470
+
471
+ | Mode | V1 status | Required behavior |
472
+ |---|---|---|
473
+ | `api-key` | Required | Resolve a profile secret and pass it to the Codex SDK for the run. |
474
+ | `codex-home` | Required | Use a profile-local Codex home containing local Codex login/config state. |
475
+ | `inherit-user` | Optional | Reuse the host user's Codex login only after explicit owner configuration. |
476
+
477
+ Acceptance criteria:
478
+
479
+ - API key mode can run Codex from a background service without an interactive Codex login.
480
+ - API keys are never shown in `/status`, `/doctor`, logs, card payloads, or exported config unless `--include-secrets --yes` is explicitly used.
481
+ - API key injection is scoped to the Codex SDK child execution and is not added to the connector process-wide environment.
482
+ - Changing auth mode invalidates incompatible session fingerprints.
483
+
484
+ ### 6.7 Codex API Key Remote Operation
485
+
486
+ Codex API key mode supports Feishu remote operation because the Feishu/Lark user does not need to be physically present at the host to complete an auth prompt.
487
+
488
+ Required behavior:
489
+
490
+ - The bridge owner configures the key locally through `profile create`, `profile set codex.api-key`, or an equivalent secret command.
491
+ - The bridge stores only a secret reference in normal config.
492
+ - The SDK runner passes the key through the SDK option or a run-scoped child environment.
493
+ - The prompt must tell Codex not to reveal or inspect bridge secret files.
494
+ - If API key resolution fails, the run rejects before Codex starts and the user receives a non-sensitive diagnostic.
495
+
496
+ Security constraints:
497
+
498
+ - Default sandbox remains `workspace-write` at most.
499
+ - `danger-full-access` is controlled by the same profile permission policy for every Codex auth mode.
500
+ - Shell/tool output is scanned for accidental key echoes before rendering when feasible.
501
+
502
+ ### 6.8 Feishu/Lark CLI Identity Projection
503
+
504
+ Profile field:
505
+
506
+ ```json
507
+ {
508
+ "feishuCli": {
509
+ "enabled": true,
510
+ "identityPreset": "bot-only",
511
+ "configDir": "~/.feishu-codex/profiles/default/feishu-cli"
512
+ }
513
+ }
514
+ ```
515
+
516
+ Supported identity presets:
517
+
518
+ | Preset | V1 status | Required behavior |
519
+ |---|---|---|
520
+ | `bot-only` | Required default | Prepare CLI config/env for the Feishu/Lark app bot identity. |
521
+ | `user-default` | Required for personal mode | Use the local user's CLI OAuth identity only when explicitly configured. |
522
+ | `disabled` | Required | Do not expose Feishu/Lark CLI credentials or config to Codex. |
523
+
524
+ Required behavior:
525
+
526
+ - Inject CLI config directory and identity env only into Codex runs.
527
+ - Keep profile CLI config separate from host-global CLI config.
528
+ - Show identity preset and health in `/status` and `/doctor`.
529
+ - Deny `user-default` in group chats unless the owner explicitly allows it.
530
+ - Add identity preset and config digest into the policy fingerprint.
531
+
532
+ Acceptance criteria:
533
+
534
+ - In `bot-only` mode, Codex can call configured Feishu/Lark CLI operations as the bot/app.
535
+ - In `user-default` mode, Codex can use the local user's CLI identity for personal chats after explicit setup.
536
+ - In `disabled` mode, Codex receives no Feishu/Lark CLI credential environment.
537
+ - Token values never appear in rendered replies, logs, or diagnostics.
538
+
539
+ ## 7. Queueing and Concurrency
540
+
541
+ ### 7.1 Debounce
542
+
543
+ Required behavior:
544
+
545
+ - Default quiet window: 600 ms.
546
+ - Multiple messages in the same scope are batched into one prompt.
547
+ - Sender annotations are included when a batch has multiple messages.
548
+
549
+ ### 7.2 Active Run Rule
550
+
551
+ Required behavior:
552
+
553
+ - At most one active Codex run per scope.
554
+ - Messages received during an active run are queued for the next run.
555
+ - Commands bypass pending queue.
556
+
557
+ ### 7.3 Global Pool
558
+
559
+ Required behavior:
560
+
561
+ - Configurable max concurrent runs.
562
+ - Excess runs wait FIFO.
563
+ - `/doctor` may use non-waiting acquire and report pool full.
564
+
565
+ ## 8. Rendering
566
+
567
+ ### 8.1 Reply Modes
568
+
569
+ Supported modes:
570
+
571
+ - `card`
572
+ - `markdown`
573
+ - `text`
574
+
575
+ Default:
576
+
577
+ ```text
578
+ card for V1, markdown/text only as fallback
579
+ ```
580
+
581
+ ### 8.2 Run Card
582
+
583
+ Card must show:
584
+
585
+ - status header
586
+ - text output
587
+ - tool calls if enabled
588
+ - terminal status
589
+ - stop button while running
590
+ - optional usage footer
591
+ - run ID or short run reference
592
+ - selected workspace suffix
593
+ - sandbox/access mode
594
+ - Codex auth mode label without secret details
595
+
596
+ ### 8.3 Stream Fallback
597
+
598
+ Required behavior:
599
+
600
+ - If streaming card creation fails, send one final markdown reply.
601
+ - If final markdown fails due to platform audit, send a neutral safe fallback.
602
+
603
+ ## 9. Attachment Handling
604
+
605
+ ### 9.1 Supported Inputs
606
+
607
+ | Resource | V1 behavior |
608
+ |---|---|
609
+ | Image | Download, cache, pass to Codex if policy accepts. |
610
+ | File | Download and include path/context if policy accepts; not necessarily passed natively. |
611
+ | Audio | Skip unless later transcribed. |
612
+ | Video | Skip unless later supported. |
613
+ | Sticker | Skip. |
614
+
615
+ ### 9.2 Policy
616
+
617
+ Default limits:
618
+
619
+ - max attachment count: 10
620
+ - max per file: 25 MB
621
+ - max per image: 25 MB
622
+ - max total per run: 100 MB
623
+ - cache TTL: 24 hours
624
+
625
+ Rejected required attachments reject the run. Optional rejected attachments are shown in prompt context as rejected.
626
+
627
+ ## 10. Access Control
628
+
629
+ ### 10.1 Defaults
630
+
631
+ - Owner can always use and administer the bot.
632
+ - Admin list is empty by default.
633
+ - Allowed users list is empty by default.
634
+ - Allowed groups list is empty by default.
635
+ - Unknown users are denied.
636
+ - Group messages require bot mention by default.
637
+
638
+ ### 10.2 Owner Resolution
639
+
640
+ Required behavior:
641
+
642
+ - Refresh owner identity from platform APIs when possible.
643
+ - Cache owner ID in runtime controls.
644
+ - If refresh fails, do not widen access.
645
+
646
+ ### 10.3 Denial Behavior
647
+
648
+ Required behavior:
649
+
650
+ - Private unauthorized messages are silently ignored.
651
+ - Group unauthorized messages are usually ignored.
652
+ - If a disallowed group mentions the bot, a short admin instruction may be sent if policy allows.
653
+
654
+ ## 11. Workspace Safety
655
+
656
+ Reject:
657
+
658
+ - empty cwd
659
+ - inaccessible path
660
+ - non-directory path
661
+ - filesystem root
662
+ - home root
663
+ - user root
664
+ - broad user folders such as Desktop or Downloads
665
+ - system roots
666
+ - temp root
667
+ - volume root
668
+
669
+ Acceptance criteria:
670
+
671
+ - Missing cwd rejects the run instead of falling back to home.
672
+ - Workspace changes clear current thread state.
673
+ - Workspace aliases cannot bypass realpath validation.
674
+
675
+ ## 12. Secrets and Local State
676
+
677
+ ### 12.1 State Directory
678
+
679
+ Default:
680
+
681
+ ```text
682
+ ~/.feishu-codex
683
+ ```
684
+
685
+ Profile files:
686
+
687
+ ```text
688
+ profiles/<profile>/config.json
689
+ profiles/<profile>/sessions.json
690
+ profiles/<profile>/session-catalog.json
691
+ profiles/<profile>/workspaces.json
692
+ profiles/<profile>/media/
693
+ profiles/<profile>/logs/
694
+ profiles/<profile>/secrets.enc
695
+ profiles/<profile>/codex-home/
696
+ profiles/<profile>/feishu-cli/
697
+ ```
698
+
699
+ ### 12.2 Secret Providers
700
+
701
+ Supported:
702
+
703
+ - encrypted local keystore
704
+ - environment variable
705
+ - file
706
+ - exec provider
707
+
708
+ Secrets must never be logged or shown in `/status`.
709
+
710
+ ## 13. Diagnostics and Observability
711
+
712
+ ### 13.1 Logs
713
+
714
+ Structured logs must include:
715
+
716
+ - profile
717
+ - scope
718
+ - run ID
719
+ - source
720
+ - event phase
721
+ - result
722
+ - timing
723
+ - sanitized error
724
+
725
+ ### 13.2 Doctor Report
726
+
727
+ Report:
728
+
729
+ - self-check
730
+ - profile
731
+ - backend
732
+ - workspace
733
+ - sandbox
734
+ - access
735
+ - owner status
736
+ - queue snapshot
737
+ - Codex availability
738
+ - echo result
739
+
740
+ ### 13.3 Optional Telemetry
741
+
742
+ Telemetry is disabled by default. If enabled, it must be adapter-based and must not block bridge operation.
743
+
744
+ ## 14. Approval Mapping
745
+
746
+ V1 does not implement Codex runtime approval mapping. It uses explicit sandbox policy and non-interactive Codex execution. The app-server architecture and data model are reserved for V2:
747
+
748
+ ```ts
749
+ interface ApprovalRequest {
750
+ id: string;
751
+ runId: string;
752
+ scopeId: string;
753
+ cwd: string;
754
+ sandbox: string;
755
+ action: string;
756
+ command?: string;
757
+ riskSummary?: string;
758
+ }
759
+ ```
760
+
761
+ V2 acceptance criteria:
762
+
763
+ - App-server runner receives approval request.
764
+ - Bridge sends signed approval card.
765
+ - Only authorized actor/admin can approve.
766
+ - Approval and denial are sent back to Codex.
767
+ - Decision is logged with sanitized action metadata.
768
+
769
+ ## 15. Non-functional Requirements
770
+
771
+ ### 15.1 Reliability
772
+
773
+ - Reconnect channel after network interruption.
774
+ - Flush local stores on shutdown.
775
+ - Protect local state with atomic writes.
776
+ - Prevent duplicate runtime per profile/app.
777
+
778
+ ### 15.2 Security
779
+
780
+ - Default no full access.
781
+ - Default no command network access.
782
+ - No plaintext app secret in config.
783
+ - No plaintext Codex API key in config.
784
+ - API key and Feishu/Lark CLI credential material are injected only into run-scoped Codex execution.
785
+ - Signed card callbacks.
786
+ - Policy-bound session resume.
787
+ - Workspace validation.
788
+ - Least-privilege group access.
789
+ - `user-default` Feishu/Lark CLI identity is disabled for group chats unless explicitly allowed.
790
+
791
+ ### 15.3 Portability
792
+
793
+ - macOS, Linux, Windows support.
794
+ - Node.js 20+ target.
795
+ - Paths normalized by platform.
796
+
797
+ ### 15.4 Maintainability
798
+
799
+ - Runner interface isolates Codex backend changes.
800
+ - Feishu/Lark gateway isolates platform SDK changes.
801
+ - Policy module owns access and sandbox decisions.
802
+ - Renderer module owns card schema.
803
+
804
+ ## 16. V1 Acceptance Checklist
805
+
806
+ - Private owner can run a Codex task.
807
+ - Allowed group can run a Codex task only when mention policy is satisfied.
808
+ - Unauthorized user cannot trigger a run.
809
+ - `/cd` switches workspace and resets session.
810
+ - Invalid workspace rejects before Codex starts.
811
+ - `/stop` interrupts an active run.
812
+ - Messages during active run queue into next run.
813
+ - Thread resumes only when cwd and policy match.
814
+ - Images are downloaded and passed to Codex when accepted.
815
+ - Run output streams back through a rich Feishu/Lark card.
816
+ - Card stop callback is signed and replay-protected.
817
+ - Markdown/text fallback works when card rendering fails.
818
+ - Codex API key auth can run without interactive Codex login.
819
+ - Codex API key is not logged, rendered, or exported by default.
820
+ - Codex receives the configured profile-local Feishu/Lark CLI identity env.
821
+ - `disabled` CLI identity mode exposes no Feishu/Lark CLI credential environment to Codex.
822
+ - `/status` shows runtime state.
823
+ - `/doctor` performs a low-sensitive echo run.
824
+ - Foreground and daemon modes work.
825
+ - Logs contain no secrets.