Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ body:
placeholder: |
1.
2.
3.
3.
validations:
required: true
- type: textarea
Expand Down
6 changes: 3 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
## Summary

-
-

## Related Task or Issue

-
-

## Verification

Expand All @@ -21,7 +21,7 @@ Commands run:

Notes:

-
-

## UI Impact

Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
*.tgz
node_modules/
dist/
.worktrees/
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
dist
coverage
.worktrees
pnpm-lock.yaml
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"printWidth": 100,
"semi": true,
"singleQuote": false,
"trailingComma": "all"
}
40 changes: 20 additions & 20 deletions AGENTDECK_PRODUCT_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ Slock-like 多 Agent 协作空间

截至 2026-05-27,社区里有很多可借鉴组件,但没有一个成熟开源方案完整覆盖 AgentDeck 的设想。

| 方向 | 代表方案 | 可借鉴点 | 不足 |
| --- | --- | --- | --- |
| 多 Agent 协作空间 | Slock | Channel / DM / thread、多 Agent、local daemon、持久记忆 | 低代码编排弱,完整开源生态不明确 |
| 低代码 Agent 平台 | Coze Studio | Agent、Workflow、Plugin、RAG、可视化低代码 | 架构较重,偏平台,不是本地 coding-agent workspace |
| LLM App 平台 | Dify | 应用、Agent、Workflow、RAG、插件、API 发布 | 更偏 AI 应用发布,不偏本地代码协作 |
| 可视化 Agent 工作流 | Flowise / Langflow | Chatflow、Agentflow、可视化搭建、API/SDK/CLI | 本地 coding agent 与安全改图能力不足 |
| 多 Agent 框架 | CrewAI / AutoGen Studio / LangGraph | 多 Agent 协作、任务分发、状态图、调试 | 更偏框架或实验台,不是完整产品 |
| coding agent runtime | OpenHands / Aider / Claude Code / Codex CLI | 代码修改、命令执行、仓库任务、沙箱能力 | 缺少 Coze-like 低代码工作流产品体验 |
| 协议层 | MCP | 标准化 tools/resources/prompts,可做 Agent 修改系统的安全工具层 | 本身不是应用框架 |
| 方向 | 代表方案 | 可借鉴点 | 不足 |
| -------------------- | ------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------- |
| 多 Agent 协作空间 | Slock | Channel / DM / thread、多 Agent、local daemon、持久记忆 | 低代码编排弱,完整开源生态不明确 |
| 低代码 Agent 平台 | Coze Studio | Agent、Workflow、Plugin、RAG、可视化低代码 | 架构较重,偏平台,不是本地 coding-agent workspace |
| LLM App 平台 | Dify | 应用、Agent、Workflow、RAG、插件、API 发布 | 更偏 AI 应用发布,不偏本地代码协作 |
| 可视化 Agent 工作流 | Flowise / Langflow | Chatflow、Agentflow、可视化搭建、API/SDK/CLI | 本地 coding agent 与安全改图能力不足 |
| 多 Agent 框架 | CrewAI / AutoGen Studio / LangGraph | 多 Agent 协作、任务分发、状态图、调试 | 更偏框架或实验台,不是完整产品 |
| coding agent runtime | OpenHands / Aider / Claude Code / Codex CLI | 代码修改、命令执行、仓库任务、沙箱能力 | 缺少 Coze-like 低代码工作流产品体验 |
| 协议层 | MCP | 标准化 tools/resources/prompts,可做 Agent 修改系统的安全工具层 | 本身不是应用框架 |

### Slock 是否开源

Expand Down Expand Up @@ -423,17 +423,17 @@ sequenceDiagram

## 13. 用户路径梳理

| 阶段 | 用户动作 | 系统响应 | 关键产物 |
| --- | --- | --- | --- |
| 初始化 | 打开 AgentDeck | 探测 Codex / Claude / Ollama / Node / Git | Runtime 状态 |
| 建立工作区 | 选择项目目录 | 绑定 workspaceRoot,读取项目 marker | Workspace |
| 创建 Agent | 设置名称、prompt、模型、权限 | 保存 AgentDefinition | Agent Registry |
| 发起任务 | 在 Chat 中 `@agent` | 创建 task,启动本地 runtime | Task Stream |
| 查看执行 | 看日志、状态、diff、产物 | 实时事件流回传 | Execution Trace |
| 编排流程 | 打开 Workflow Canvas | 创建 Start / Agent / Tool / Condition / Human Approval / End | WorkflowDefinition |
| 自然语言改流程 | 在 Chat 中描述修改 | Coding agent 生成 patch proposal | PatchProposal |
| 审批发布 | 查看 diff 并确认 | 校验、apply、生成版本 | 新 workflow version |
| 回滚审计 | 查看历史修改 | 展示谁改了什么、何时改、为何改 | Audit Log / Rollback |
| 阶段 | 用户动作 | 系统响应 | 关键产物 |
| -------------- | ---------------------------- | ------------------------------------------------------------ | -------------------- |
| 初始化 | 打开 AgentDeck | 探测 Codex / Claude / Ollama / Node / Git | Runtime 状态 |
| 建立工作区 | 选择项目目录 | 绑定 workspaceRoot,读取项目 marker | Workspace |
| 创建 Agent | 设置名称、prompt、模型、权限 | 保存 AgentDefinition | Agent Registry |
| 发起任务 | 在 Chat 中 `@agent` | 创建 task,启动本地 runtime | Task Stream |
| 查看执行 | 看日志、状态、diff、产物 | 实时事件流回传 | Execution Trace |
| 编排流程 | 打开 Workflow Canvas | 创建 Start / Agent / Tool / Condition / Human Approval / End | WorkflowDefinition |
| 自然语言改流程 | 在 Chat 中描述修改 | Coding agent 生成 patch proposal | PatchProposal |
| 审批发布 | 查看 diff 并确认 | 校验、apply、生成版本 | 新 workflow version |
| 回滚审计 | 查看历史修改 | 展示谁改了什么、何时改、为何改 | Audit Log / Rollback |

## 14. MVP 用户故事

Expand Down
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

AgentDeck is a local-first workspace for multi-agent coding and low-code orchestration.

The project is in early design and planning. Current work is focused on defining the product, architecture, security model, UI direction, and development backlog before implementation begins.
The project is in early development. Current work is focused on turning the product design into a small, testable monorepo: runtime detection, local daemon, agent registry, chat workspace, workflow core, workflow canvas, and safe patch approval.

## What AgentDeck Is

Expand All @@ -13,12 +13,30 @@ AgentDeck is designed to combine:
- Low-code Agent and Workflow DAG orchestration.
- Safe chat-to-workflow editing through patch proposals, validation, diff preview, approval, and rollback.

## MVP Scope

The MVP focuses on:

- Runtime Detector
- Agent Registry
- Chat Workspace
- Local Daemon
- Workflow Canvas
- Workflow Patch Approval

The MVP intentionally excludes multi-tenant enterprise permissions, cloud-hosted execution, billing, plugin marketplace, full RAG, custom model training, and full Dify/Coze-style app publishing.

## Project Documents

- Product design: [`AGENTDECK_PRODUCT_DESIGN.md`](AGENTDECK_PRODUCT_DESIGN.md)
- Original project brief: [`agentdeck-project-brief.md`](agentdeck-project-brief.md)
- Development plan: [`docs/development/README.md`](docs/development/README.md)
- Task backlog: [`docs/development/task-backlog.md`](docs/development/task-backlog.md)
- Architecture: [`docs/architecture.md`](docs/architecture.md)
- Runtime adapters: [`docs/runtime-adapters.md`](docs/runtime-adapters.md)
- Workflow schema: [`docs/workflow-schema.md`](docs/workflow-schema.md)
- Security model: [`docs/security-model.md`](docs/security-model.md)
- Contributing guide: [`docs/contributing.md`](docs/contributing.md)
- Agent instructions: [`AGENTS.md`](AGENTS.md)
- Claude Code instructions: [`CLAUDE.md`](CLAUDE.md)

Expand Down
19 changes: 9 additions & 10 deletions agentdeck-project-brief.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ Slock-like 多 Agent 协作空间

截至 2026-05-27,社区里有很多可借鉴组件,但没有一个完整覆盖本项目设想的成熟开源方案。

| 方向 | 代表方案 | 可借鉴点 | 不足 |
| --- | --- | --- | --- |
| 多 Agent 协作空间 | Slock | Channel / DM / thread、多 Agent、local daemon、持久记忆 | 低代码编排弱,完整开源生态不明确 |
| 低代码 Agent 平台 | Coze Studio | Agent、Workflow、Plugin、RAG、可视化低代码 | 架构较重,偏平台,不是本地 coding-agent workspace |
| LLM App 平台 | Dify | 应用、Agent、Workflow、RAG、插件、API 发布 | 更偏 AI 应用发布,不偏本地代码协作 |
| 可视化 Agent 工作流 | Flowise / Langflow | Chatflow、Agentflow、可视化搭建、API/SDK/CLI | 本地 coding agent 与安全改图能力不足 |
| 多 Agent 框架 | CrewAI / AutoGen Studio / LangGraph | 多 Agent 协作、任务分发、状态图、调试 | 更偏框架或实验台,不是完整产品 |
| coding agent runtime | OpenHands / Aider / Claude Code / Codex CLI | 代码修改、命令执行、仓库任务、沙箱能力 | 缺少 Coze-like 低代码工作流产品体验 |
| 协议层 | MCP | 标准化 tools/resources/prompts,可做 Agent 修改系统的安全工具层 | 本身不是应用框架 |
| 方向 | 代表方案 | 可借鉴点 | 不足 |
| -------------------- | ------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------- |
| 多 Agent 协作空间 | Slock | Channel / DM / thread、多 Agent、local daemon、持久记忆 | 低代码编排弱,完整开源生态不明确 |
| 低代码 Agent 平台 | Coze Studio | Agent、Workflow、Plugin、RAG、可视化低代码 | 架构较重,偏平台,不是本地 coding-agent workspace |
| LLM App 平台 | Dify | 应用、Agent、Workflow、RAG、插件、API 发布 | 更偏 AI 应用发布,不偏本地代码协作 |
| 可视化 Agent 工作流 | Flowise / Langflow | Chatflow、Agentflow、可视化搭建、API/SDK/CLI | 本地 coding agent 与安全改图能力不足 |
| 多 Agent 框架 | CrewAI / AutoGen Studio / LangGraph | 多 Agent 协作、任务分发、状态图、调试 | 更偏框架或实验台,不是完整产品 |
| coding agent runtime | OpenHands / Aider / Claude Code / Codex CLI | 代码修改、命令执行、仓库任务、沙箱能力 | 缺少 Coze-like 低代码工作流产品体验 |
| 协议层 | MCP | 标准化 tools/resources/prompts,可做 Agent 修改系统的安全工具层 | 本身不是应用框架 |

结论:最优策略不是直接 fork Coze/Dify,而是借鉴它们的模型,自研本地 daemon、Chat 协作层和 workflow patch 安全层。

Expand Down Expand Up @@ -529,4 +529,3 @@ Phase 5: Memory、Audit、Plugin/MCP 市场
- OpenAI Codex CLI: https://developers.openai.com/codex/cli
- Ollama Codex integration: https://docs.ollama.com/integrations/codex
- Model Context Protocol: https://modelcontextprotocol.wiki/en/introduction

17 changes: 17 additions & 0 deletions apps/daemon/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@agentdeck/daemon",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "echo \"@agentdeck/daemon dev server is not scaffolded yet\"",
"build": "tsc -p tsconfig.json",
"test": "echo \"@agentdeck/daemon tests are not scaffolded yet\"",
"lint": "echo \"@agentdeck/daemon lint is not scaffolded yet\"",
"typecheck": "tsc -p tsconfig.json --noEmit",
"format": "echo \"@agentdeck/daemon format is not scaffolded yet\""
},
"dependencies": {
"@agentdeck/runtime-adapters": "workspace:*"
}
}
46 changes: 46 additions & 0 deletions apps/daemon/src/events/event-bus.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { describe, expect, it } from "vitest";

import { createEventBus } from "./event-bus.js";
import type { DaemonEvent } from "./event-types.js";

function taskStartedEvent(id: string): DaemonEvent {
return {
id,
type: "task.started",
createdAt: "2026-05-28T00:00:00.000Z",
payload: {
taskId: "task-1",
title: "Run workflow",
},
};
}

describe("createEventBus", () => {
it("broadcasts events to multiple subscribers", () => {
const bus = createEventBus();
const first: DaemonEvent[] = [];
const second: DaemonEvent[] = [];

bus.subscribe((event) => first.push(event));
bus.subscribe((event) => second.push(event));
bus.publish(taskStartedEvent("event-1"));

expect(first.map((event) => event.id)).toEqual(["event-1"]);
expect(second.map((event) => event.id)).toEqual(["event-1"]);
expect(bus.subscriberCount()).toBe(2);
});

it("removes subscribers when they unsubscribe", () => {
const bus = createEventBus();
const received: DaemonEvent[] = [];

const subscription = bus.subscribe((event) => received.push(event));
expect(bus.subscriberCount()).toBe(1);

subscription.unsubscribe();
bus.publish(taskStartedEvent("event-2"));

expect(received).toEqual([]);
expect(bus.subscriberCount()).toBe(0);
});
});
35 changes: 35 additions & 0 deletions apps/daemon/src/events/event-bus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { DaemonEvent } from "./event-types.js";

export interface EventSubscription {
readonly unsubscribe: () => void;
}

export interface EventBus {
readonly publish: (event: DaemonEvent) => void;
readonly subscribe: (listener: (event: DaemonEvent) => void) => EventSubscription;
readonly subscriberCount: () => number;
}

export function createEventBus(): EventBus {
const listeners = new Set<(event: DaemonEvent) => void>();

return {
publish(event) {
for (const listener of listeners) {
listener(event);
}
},
subscribe(listener) {
listeners.add(listener);

return {
unsubscribe() {
listeners.delete(listener);
},
};
},
subscriberCount() {
return listeners.size;
},
};
}
17 changes: 17 additions & 0 deletions apps/daemon/src/events/event-types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { describe, expect, it } from "vitest";

import { DAEMON_EVENT_TYPES } from "./event-types.js";

describe("DAEMON_EVENT_TYPES", () => {
it("defines all MVP daemon event types", () => {
expect(DAEMON_EVENT_TYPES).toEqual([
"runtime.detected",
"task.started",
"task.output",
"task.diff",
"task.approvalRequested",
"task.completed",
"task.failed",
]);
});
});
86 changes: 86 additions & 0 deletions apps/daemon/src/events/event-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import type { RuntimeStatus } from "@agentdeck/runtime-adapters";

export const DAEMON_EVENT_TYPES = [
"runtime.detected",
"task.started",
"task.output",
"task.diff",
"task.approvalRequested",
"task.completed",
"task.failed",
] as const;

export type DaemonEventType = (typeof DAEMON_EVENT_TYPES)[number];

export interface DaemonEventBase<TType extends DaemonEventType, TPayload> {
readonly id: string;
readonly type: TType;
readonly createdAt: string;
readonly payload: TPayload;
}

export type RuntimeDetectedEvent = DaemonEventBase<
"runtime.detected",
{
readonly runtimeId: string;
readonly status: RuntimeStatus;
}
>;

export type TaskStartedEvent = DaemonEventBase<
"task.started",
{
readonly taskId: string;
readonly title: string;
}
>;

export type TaskOutputEvent = DaemonEventBase<
"task.output",
{
readonly taskId: string;
readonly stream: "stdout" | "stderr";
readonly text: string;
}
>;

export type TaskDiffEvent = DaemonEventBase<
"task.diff",
{
readonly taskId: string;
readonly diff: string;
}
>;

export type TaskApprovalRequestedEvent = DaemonEventBase<
"task.approvalRequested",
{
readonly taskId: string;
readonly reason: string;
}
>;

export type TaskCompletedEvent = DaemonEventBase<
"task.completed",
{
readonly taskId: string;
readonly exitCode: number;
}
>;

export type TaskFailedEvent = DaemonEventBase<
"task.failed",
{
readonly taskId: string;
readonly message: string;
}
>;

export type DaemonEvent =
| RuntimeDetectedEvent
| TaskStartedEvent
| TaskOutputEvent
| TaskDiffEvent
| TaskApprovalRequestedEvent
| TaskCompletedEvent
| TaskFailedEvent;
Loading