Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
39c80d3
✨ feat: add GitHub and Lark auth plugins for OAuth app credentials
vaayne Apr 21, 2026
1b49ecd
✨ feat: add oauthcli package with device-flow broker and token manager
vaayne Apr 21, 2026
1110eaf
✨ feat: add OAuth CLI profile API routes and UI
vaayne Apr 21, 2026
dd8cdfa
✨ feat: add CLI wrapper provisioning and runner OAuth env injection
vaayne Apr 21, 2026
ae44000
✨ feat: inject wrapper PATH in Docker sessions and add gh/lark-cli to…
vaayne Apr 21, 2026
4247d14
✨ feat: add tests and docs for OAuth CLI feature
vaayne Apr 21, 2026
0017689
♻️ refactor: remove hardcoded gh and lark-cli from dockerfile
vaayne Apr 22, 2026
e11c4b6
♻️ refactor(oauthcli): use golang.org/x/oauth2 for GitHub device flow…
vaayne Apr 22, 2026
69f88aa
♻️ refactor(oauthcli): simplify vault generics, remove dead lark secr…
vaayne Apr 22, 2026
bce0b4c
♻️ refactor(oauthcli): use oauth2 library for all Lark token flows
vaayne Apr 22, 2026
324799d
♻️ refactor(oauthcli): switch Lark to v2 OAuth endpoint, remove custo…
vaayne Apr 22, 2026
9f30a36
✨ feat(oauthcli): expand GitHub OAuth scopes for human-level CLI access
vaayne Apr 22, 2026
40787ce
✨ feat(oauthcli): add offline_access scope and fix Lark scope declara…
vaayne Apr 22, 2026
02f486b
✨ feat(oauthcli): expand Lark scopes for daily Feishu life management
vaayne Apr 22, 2026
d5c36fa
🐛 fix(config): seed auth/github and auth/lark plugins on startup
vaayne Apr 22, 2026
cc5733b
✨ feat(oauthcli): add redirect_url config and fix Lark callback auth
vaayne Apr 22, 2026
7b7ac25
format
vaayne Apr 22, 2026
e8db71a
✨ feat(admin): improve skills UI and Lark integration
vaayne Apr 22, 2026
c8d0f45
✨ feat(admin): add URL-based routing for session detail view
Apr 22, 2026
12051a3
♻️ refactor: remove macOS sandbox-exec and update oauthcli/lark deps
Apr 22, 2026
1803b8c
✨ test: add unit tests for OAuth CLI auth plugins and improve oauthcl…
Apr 22, 2026
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
2 changes: 1 addition & 1 deletion cmd/anna/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ func modelSwitcher(base *config.Snapshot, store config.Store, pool *agent.Pool,
snap.Providers = providers
}

factory, err := agent.NewRunnerFactory(&snap, builtinTools, pluginToolsBuilder, providerRegistryBuilder, promptToolsFn, promptSectionsFn, toolLifecycle, skillStore, nil, nil)
factory, err := agent.NewRunnerFactory(&snap, builtinTools, pluginToolsBuilder, providerRegistryBuilder, promptToolsFn, promptSectionsFn, toolLifecycle, skillStore, nil, nil, nil)
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/anna/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func TestNewRunnerFactoryGo(t *testing.T) {
}
snap.Workspace = t.TempDir()

factory, err := agent.NewRunnerFactory(snap, nil, nil, testProviderRegistryBuilder, nil, nil, nil, nil, nil, nil)
factory, err := agent.NewRunnerFactory(snap, nil, nil, testProviderRegistryBuilder, nil, nil, nil, nil, nil, nil, nil)
if err != nil {
t.Fatalf("NewRunnerFactory: %v", err)
}
Expand All @@ -182,7 +182,7 @@ func TestNewRunnerFactoryUnknown(t *testing.T) {
Runner: config.RunnerConfig{Type: "invalid"},
}

_, err := agent.NewRunnerFactory(snap, nil, nil, testProviderRegistryBuilder, nil, nil, nil, nil, nil, nil)
_, err := agent.NewRunnerFactory(snap, nil, nil, testProviderRegistryBuilder, nil, nil, nil, nil, nil, nil, nil)
if err == nil {
t.Fatal("expected error for unknown runner type")
}
Expand Down Expand Up @@ -290,7 +290,7 @@ func TestModelSwitcherPreservesPromptBuilders(t *testing.T) {
}
snap.Workspace = t.TempDir()

initialFactory, err := agent.NewRunnerFactory(snap, nil, nil, testProviderRegistryBuilder, nil, nil, nil, nil, nil, nil)
initialFactory, err := agent.NewRunnerFactory(snap, nil, nil, testProviderRegistryBuilder, nil, nil, nil, nil, nil, nil, nil)
if err != nil {
t.Fatalf("NewRunnerFactory: %v", err)
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/anna/plugins_imports.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package main

import (
// Plugin auth.
_ "github.com/vaayne/anna/plugins/auth/github"
_ "github.com/vaayne/anna/plugins/auth/lark"

// Plugin channels.
_ "github.com/vaayne/anna/plugins/channels/feishu"
_ "github.com/vaayne/anna/plugins/channels/qq"
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/channels/feishu.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ anna now ships a generated builtin `lark` system skill, and release builds embed
Typical setup:

```bash
command -v lark-cli
npm install -g @larksuite/cli
command -v lark-cli || npm install -g @larksuite/cli
lark-cli config init --new
lark-cli auth login --recommend
lark-cli auth status
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/channels/feishu.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ anna 现在会内置生成好的 `lark` system skill,发布构建也会自动
常见初始化流程:

```bash
command -v lark-cli
npm install -g @larksuite/cli
command -v lark-cli || npm install -g @larksuite/cli
lark-cli config init --new
lark-cli auth login --recommend
lark-cli auth status
Expand Down
20 changes: 10 additions & 10 deletions docs/content/docs/core/sandbox-backend-abstraction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ title: Sandbox Backend Abstraction

## Status

Implemented. Docker is the recommended sandbox backend. A local backend is also available for Docker-free environments with OS-level hardening. Anna's execution boundary is described by `pkg/sandbox` contracts, with runner-facing registry wiring in `internal/sandbox`.
Implemented. Docker is the recommended sandbox backend. A local backend is also available for Docker-free environments; Linux keeps OS-level hardening, while macOS currently runs local commands directly on the host without additional sandboxing. Anna's execution boundary is described by `pkg/sandbox` contracts, with runner-facing registry wiring in `internal/sandbox`.

## Purpose

The sandbox abstraction exists so runner code, plugin wiring, and tool execution do not depend on concrete backend types. All sandboxed execution runs through a Docker container. Docker is required; Anna fails closed when the Docker daemon is unavailable at session-create time.
The sandbox abstraction exists so runner code, plugin wiring, and tool execution do not depend on concrete backend types. Execution always runs through the active backend selected by the runner. Docker provides the strongest isolation; the local backend is a host-execution fallback for environments where Docker is unavailable or undesirable.

The top-level model is:

Expand Down Expand Up @@ -58,9 +58,9 @@ The local backend runs commands directly on the host OS. It is intended for envi
| Process group kill + rlimits | All Unix | `SIGKILL` on process group; `RLIMIT_FSIZE`, `RLIMIT_NOFILE`, `RLIMIT_CPU` via `prlimit(2)` |
| Filesystem + network isolation | Linux (bwrap available) | `bwrap` — workspace bind-mounted to `/workspace`; rest of FS read-only; optional `--unshare-net` |
| Network isolation only | Linux (no bwrap) | `unshare --net` — new network namespace, no outbound connectivity |
| Filesystem + network policy | macOS | `sandbox-exec` Seatbelt profile — write restricted to workspace; network per policy |
| No additional local isolation | macOS | Commands run directly on the host OS; filesystem and network policy are not enforced |

The local backend uses a **fail-closed** strategy: if a required isolation tool is missing, session creation fails with an actionable error message rather than running unconfined.
The local backend uses a **fail-closed** strategy on Linux: if a required isolation tool is missing, session creation fails with an actionable error message rather than running unconfined. On macOS, no extra sandboxing tool is currently applied.

#### Installing dependencies

Expand All @@ -78,8 +78,8 @@ pacman -S bubblewrap

`unshare` (network-only fallback) is part of `util-linux` and is present on virtually all Linux systems.

**macOS — sandbox-exec:**
Built into macOS. No installation required. Note: `sandbox-exec` has been informally deprecated since macOS 10.15 (Catalina). It remains functional but may be removed in a future macOS release.
**macOS:**
No additional dependency is required. The current local backend runs commands directly on the host OS without applying a macOS-specific sandbox.

**Windows:** Not supported. Use the Docker backend.

Expand All @@ -91,14 +91,14 @@ On Linux with `bwrap`, the agent always sees its workspace at `/workspace` regar

Per-agent sandbox configuration is limited to network policy (mode and allowlist). Each agent independently controls whether its sandbox allows outbound network access and which hosts are reachable.

Network modes supported by the Docker backend:
Network modes supported by Docker and by the Linux local backend:

| Mode | Description |
| ----------- | ------------------------------------ |
| `disabled` | No outbound network access (default) |
| `allow_all` | Unrestricted outbound access |

The `whitelist` mode is removed. Anna validates the configured mode at session-create time and fails closed if the backend cannot enforce it.
The `whitelist` mode is removed. Docker and the Linux local backend validate the configured mode at session-create time and fail closed if the backend cannot enforce it. The macOS local backend currently ignores network policy and runs with host network access.

## Current Architecture

Expand All @@ -108,7 +108,7 @@ The runner creates a `sandbox.Session` for each run and keeps ownership of its l

### Backend resolution

The Docker backend self-registers in `internal/sandbox` via `init()`. `pkg/sandbox.Registry.CreateSession` iterates registered factories in registration order and uses the first available factory that supports the policy. With only one factory registered, this always selects Docker or fails.
The runner resolves the active backend from plugin state and dispatches to a backend-specific factory. Built-in factories currently support `docker` and `local`.

### Execution-time mediation

Expand All @@ -122,7 +122,7 @@ All local execution paths that must obey sandbox policy are mediated through the

### stdio-MCP benefit

`Session.StartProcess` is fully supported by the Docker backend on every run. This means MCP stdio transports work uniformly across all platforms without requiring platform-specific subprocess handling.
`Session.StartProcess` is supported by both built-in backends. Docker gives stdio MCP servers a dedicated container process namespace; the local backend starts them directly on the host OS.

### Non-runner filesystem access

Expand Down
20 changes: 10 additions & 10 deletions docs/content/docs/core/sandbox-backend-abstraction.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ title: 沙箱后端抽象

## 状态

已实现。Docker 是推荐的沙箱后端。本地后端也可用于无 Docker 环境,并应用了操作系统级加固措施。Anna 的执行边界由 `pkg/sandbox` 契约描述,runner 侧注册配置位于 `internal/sandbox`。
已实现。Docker 是推荐的沙箱后端。本地后端也可用于无 Docker 环境;Linux 保留操作系统级加固,而 macOS 当前会直接在宿主机上运行本地命令,不再附加额外沙箱。Anna 的执行边界由 `pkg/sandbox` 契约描述,runner 侧注册配置位于 `internal/sandbox`。

## 目的

沙箱抽象的目的是使 runner 代码、插件配置和工具执行不依赖于具体的后端类型。所有沙箱化执行都在 Docker 容器中运行。Docker 是必要条件;当 Docker 守护进程在会话创建时不可用时,Anna 会拒绝失败(fail closed)
沙箱抽象的目的是使 runner 代码、插件配置和工具执行不依赖于具体的后端类型。执行总是通过 runner 选中的活动后端进行。Docker 提供最强隔离;本地后端则是在 Docker 不可用或不想使用时的宿主机执行回退方案

顶层模型:

Expand Down Expand Up @@ -58,9 +58,9 @@ Docker 提供完整的容器级进程、文件系统和网络隔离。Docker 守
| 进程组终止 + 资源限制 | 所有 Unix | 对进程组发送 `SIGKILL`;通过 `prlimit(2)` 设置 `RLIMIT_FSIZE`、`RLIMIT_NOFILE`、`RLIMIT_CPU` |
| 文件系统 + 网络隔离 | Linux(bwrap 可用) | `bwrap` — 工作区绑定挂载到 `/workspace`;其余文件系统只读;可选 `--unshare-net` |
| 仅网络隔离 | Linux(无 bwrap) | `unshare --net` — 新建网络命名空间,无出站连接 |
| 文件系统 + 网络策略 | macOS | `sandbox-exec` Seatbelt 配置文件 — 写入限制在工作区;网络按策略控制 |
| 无额外本地隔离 | macOS | 命令直接在宿主机 OS 上运行;不强制执行文件系统和网络策略 |

本地后端采用**拒绝失败**策略:如果所需的隔离工具缺失,会话创建失败并返回包含操作建议的错误信息,而非在无隔离状态下运行。
本地后端在 Linux 上采用**拒绝失败**策略:如果所需的隔离工具缺失,会话创建失败并返回包含操作建议的错误信息,而非在无隔离状态下运行。macOS 当前不再附加额外沙箱工具

#### 安装依赖

Expand All @@ -78,8 +78,8 @@ pacman -S bubblewrap

`unshare`(仅网络隔离的备用方案)是 `util-linux` 的一部分,在几乎所有 Linux 系统上均已存在。

**macOS — sandbox-exec:**
macOS 内置,无需安装。注意:`sandbox-exec` 自 macOS 10.15(Catalina)起已被非正式弃用,仍可使用,但可能在未来的 macOS 版本中被移除
**macOS:**
无需额外依赖。当前本地后端直接在宿主机 OS 上运行命令,不应用特定于 macOS 的沙箱

**Windows:** 不支持,请使用 Docker 后端。

Expand All @@ -91,14 +91,14 @@ macOS 内置,无需安装。注意:`sandbox-exec` 自 macOS 10.15(Catalina

每个代理的沙箱配置仅限于网络策略(模式和允许列表)。每个代理独立控制其沙箱是否允许出站网络访问以及哪些主机可达。

Docker 后端支持的网络模式
Docker 后端以及 Linux 本地后端支持的网络模式

| 模式 | 描述 |
| ----------- | ---------------------------- |
| `disabled` | 禁止所有出站网络访问(默认) |
| `allow_all` | 不受限制的出站访问 |

`whitelist` 模式已移除。Anna 在会话创建时验证已配置的模式,如果后端无法强制执行则拒绝失败。
`whitelist` 模式已移除。Docker 和 Linux 本地后端会在会话创建时验证已配置的模式,如果后端无法强制执行则拒绝失败。macOS 本地后端当前会忽略网络策略并使用宿主机网络访问

## 当前架构

Expand All @@ -108,7 +108,7 @@ runner 为每次运行创建一个 `sandbox.Session` 并持有其生命周期所

### 后端解析

Docker 后端通过 `init()` 在 `internal/sandbox` 中自注册。`pkg/sandbox.Registry.CreateSession` 按注册顺序迭代已注册的工厂,使用第一个可用且支持该策略的工厂。由于只注册了一个工厂,这总是选择 Docker 或失败
runner 会根据插件状态解析当前活动后端,并分派到对应的后端工厂。内置工厂当前支持 `docker` 和 `local`

### 执行时中介

Expand All @@ -122,7 +122,7 @@ Docker 后端通过 `init()` 在 `internal/sandbox` 中自注册。`pkg/sandbox.

### stdio-MCP 优势

Docker 后端在每次运行时完全支持 `Session.StartProcess`。这意味着 MCP stdio 传输在所有平台上均可统一工作,无需特定于平台的子进程处理
两个内置后端都支持 `Session.StartProcess`。Docker 为 stdio MCP 服务器提供独立的容器进程命名空间;本地后端则直接在宿主机上启动这些进程

### 非 runner 文件系统访问

Expand Down
16 changes: 8 additions & 8 deletions docs/content/docs/features/agent-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ A template is a complete starting point for a new agent. When you click **Add ag

- **Model** — provider/model pair the template recommends
- **System prompt** — copied from the template's referenced soul
- **Enabled builtin skills** — shown as chips on the form; togglable before save
- **Builtin skill metadata** — retained for compatibility with older templates, but system-scope builtin skills are now always available to every agent

User-supplied fields always win. You can edit every field on the form before saving, and after save the agent has no persistent link back to the template — upgrading a template does not touch existing agents.

Expand All @@ -46,22 +46,22 @@ Sub-agent presets describe tool-restricted workers for the `agent` delegation to

Shipped sub-agents: `coder`, `researcher`, `reviewer`, `writer`.

## Skills and per-agent enablement
## Skills

Every skill marked `scope='system'` is universal by design, which means naive growth of the builtin catalog would drop every skill into every agent's prompt — fast prompt bloat.
Every skill synced into the database with `scope='system'` is available to every agent automatically.

The fix: `settings_agents.enabled_builtin_skills` (JSON array of skill names). An agent's skill catalog in the prompt is:
An agent's skill catalog in the prompt is:

```
{always-on builtins: anna}
∪ {enabled_builtin_skills}
{all system-scope builtin skills}
∪ {agent-scope DB skills}
∪ {user-scope DB skills}
∪ {project skills from .agents/skills}
```

`anna` (the self-knowledge skill) is always on. Every other builtin skill must be opted in — either via the template you picked (which sets the list for you) or by toggling chips on the agent form.
The legacy `settings_agents.enabled_builtin_skills` field is still stored for backward compatibility with older templates and agent rows, but it no longer filters prompt visibility.

Shipped skills: `anna`, `code-review`, `docs-writing`, `implementation`, `research`, `task-planning`.
Shipped system skills live under `internal/resources/skills/system/` and are synced into `skills(scope='system')` on startup. Startup sync is authoritative: skills removed from the embedded system catalog are deleted from the database on the next sync.

## Adding a new builtin resource

Expand Down
16 changes: 8 additions & 8 deletions docs/content/docs/features/agent-templates.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Anna 自带一套**内置资源目录**,让全新安装即开即用,无需

- **模型** — 模板推荐的 provider/model 组合
- **系统提示** — 复制自模板引用的 soul
- **已启用的内置技能** — 以芯片形式显示在表单上,保存前可自由切换
- **内置技能元数据** — 为兼容旧模板而保留,但 `scope='system'` 的内置技能现已自动对所有 agent 可用

用户手动输入始终优先。所有字段在保存前都可以编辑;保存之后 agent 与模板没有任何持久关联 — 更新模板不会影响已有 agent。

Expand All @@ -46,22 +46,22 @@ Sub-agent 预设定义了 `agent` 委派工具使用的受限工作者(调研

附带的 sub-agent:`coder`、`researcher`、`reviewer`、`writer`。

## Skill 与按 agent 开关
## Skill

每个 `scope='system'` 的技能天生对所有 agent 可见,因此朴素地增长内置技能目录会把所有技能同时塞进每个 agent 的提示 — 提示体积会迅速膨胀
所有同步到数据库且 `scope='system'` 的技能,都会自动对所有 agent 可用

解决方式:`settings_agents.enabled_builtin_skills`(JSON 字符串数组)。agent 看到的技能目录为
agent 在提示里看到的技能目录为

```
{常驻内置:anna}
∪ {enabled_builtin_skills 中列出的}
{全部 system 范围内置技能}
∪ {agent 范围的数据库技能}
∪ {user 范围的数据库技能}
∪ {来自 .agents/skills 的 project 技能}
```

`anna`(自我知识技能)永远启用。其他内置技能必须显式开启 — 通过你选择的模板(模板会替你设好)或手动切换表单上的芯片
历史遗留的 `settings_agents.enabled_builtin_skills` 字段仍会保留,以兼容旧模板和旧 agent 行,但它已不再参与提示可见性的过滤

附带的技能:`anna`、`code-review`、`docs-writing`、`implementation`、`research`、`task-planning`
附带的 system skill 位于 `internal/resources/skills/system/`,启动时会同步到 `skills(scope='system')`。启动同步是权威来源:如果某个嵌入式 system skill 已从目录中移除,那么下一次同步时也会从数据库中删除

## 新增一个内置资源

Expand Down
Loading
Loading