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/LICENSE +21 -0
- package/README.md +169 -0
- package/README.zh.md +170 -0
- package/bin/feishu-codex.mjs +8 -0
- package/dist/chunk-AOVT2UMM.js +3876 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +454 -0
- package/dist/index.d.ts +994 -0
- package/dist/index.js +144 -0
- package/docs/ARCHITECTURE.md +691 -0
- package/docs/COMMAND_COMPLETION_SPEC.md +92 -0
- package/docs/FEATURE_PARITY_SPEC.md +104 -0
- package/docs/FEISHU_PERMISSIONS.md +24 -0
- package/docs/SPEC.md +825 -0
- package/package.json +93 -0
|
@@ -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
|