Skip to content

Commit ea3f247

Browse files
authored
Merge branch 'main' into feat/byoc-runtime-updates
2 parents c00849d + 660a187 commit ea3f247

48 files changed

Lines changed: 1505 additions & 76 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
> [!IMPORTANT]
1515
> OpenAgentPack is in beta. Public APIs and the `agents.yaml` schema may change before `1.0`. See the [changelog](./CHANGELOG.md).
1616
17-
<p align="center">
18-
<img src="https://img.alicdn.com/imgextra/i3/O1CN01xWDp5P1EP90HOZx9q_!!6000000000343-2-tps-1254-1254.png" width="360" alt="OpenAgentPack: one agents.yaml for multiple managed-agent providers">
19-
</p>
17+
![OpenAgentPack CLI: from agents.yaml to plan and apply](./packages/sdk/docs/agents.gif)
18+
19+
`agents.yaml → validate → plan → apply`: bring agents back into Git, review the pending changes, then update remote resources.
2020

2121
One `agents.yaml` defines an agent's environment, model, instructions, tools, skills, MCP servers, vaults, and credentials. Review every change in a PR, preview it with `plan`, and apply it when ready — instead of rebuilding the same agent through console clicks.
2222

@@ -33,6 +33,8 @@ agents validate && agents plan
3333

3434
[Run the 5-minute quick start](./docs/getting-started.md) · [View provider support](./docs/reference/providers.md) · [Browse runnable examples](./docs/examples.md) · [Roadmap](./ROADMAP.md)
3535

36+
[Watch the Playground demo: switch provider and run the same agent scenario](https://github.com/user-attachments/assets/bf51b8d8-f2ed-464b-bca9-0709fefcc44d)
37+
3638
## Why now
3739

3840
Agents are moving from personal tools to enterprise digital workers. But the things that make an agent valuable — its prompts, skills, knowledge files, tools, and runtime configuration — still live mainly inside cloud-provider consoles.
@@ -45,6 +47,10 @@ OpenAgentPack puts a declarative control plane between the agent and the cloud p
4547

4648
The goal is to make an agent an enterprise-controlled, portable, and inheritable digital asset.
4749

50+
<p align="center">
51+
<img src="https://img.alicdn.com/imgextra/i3/O1CN01xWDp5P1EP90HOZx9q_!!6000000000343-2-tps-1254-1254.png" width="360" alt="OpenAgentPack: one agents.yaml for multiple managed-agent providers">
52+
</p>
53+
4854
### Declaration and portability: the agent as a blueprint
4955

5056
Borrowing Docker's declarative idea, OpenAgentPack brings everything that determines what an agent is — model, instructions, tools, skills, environment, files, and credential references — into one `agents.yaml` blueprint. The blueprint can live in Git, pass through pull-request review, reproduce an agent, and move across providers.
@@ -68,18 +74,6 @@ The mechanics are a single `agents.yaml`, a `validate → plan → apply` workfl
6874
- **Dependency-aware** — Environment → Skill → Agent are created in topological order; a failed dependency skips its dependents instead of leaving half-built state.
6975
- **Drift recovery** — detects when remote config has drifted from your declaration and reconciles it. The YAML is always the single source of truth.
7076

71-
## Demo
72-
73-
### CLI workflow
74-
75-
![OpenAgentPack CLI workflow](./packages/sdk/docs/agents.gif)
76-
77-
### Local Playground
78-
79-
`agents playground` launches a local WebUI, fetches the matching `@openagentpack/playground` package on demand, and opens it in your browser. Use `--provider` to target `bailian`, `qoder`, `ark`, or `claude`.
80-
81-
[Watch the Playground demo video](https://github.com/user-attachments/assets/bf51b8d8-f2ed-464b-bca9-0709fefcc44d)
82-
8377
## Quick start
8478

8579
```bash
@@ -90,6 +84,10 @@ agents apply -y # apply changes
9084
agents destroy # tear down managed resources
9185
```
9286

87+
Run `agents playground` to launch the local WebUI, and use `--provider` to target `bailian`, `qoder`, `ark`, or `claude`. You can switch providers on the same declaration, run real sessions, and observe tool calls and artifacts.
88+
89+
[Watch the full Playground demo](https://github.com/user-attachments/assets/bf51b8d8-f2ed-464b-bca9-0709fefcc44d)
90+
9391
A minimal config:
9492

9593
```yaml

README.zh-CN.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
> [!IMPORTANT]
1515
> OpenAgentPack 目前处于 Beta 阶段。公开 API 和 `agents.yaml` Schema 在 `1.0` 前仍可能发生不兼容变更,详见 [更新日志](./CHANGELOG.md)
1616
17-
<p align="center">
18-
<img src="https://img.alicdn.com/imgextra/i1/O1CN016pw0Ax1KuBXckX0Iz_!!6000000001223-2-tps-1254-1254.png" width="360" alt="OpenAgentPack:一份 agents.yaml 管理多个托管 Agent 平台">
19-
</p>
17+
![OpenAgentPack CLI:从 agents.yaml 到 plan 和 apply](./packages/sdk/docs/agents.gif)
18+
19+
`agents.yaml → validate → plan → apply`:先把 Agent 带回 Git,审查将要发生的变更,再更新远端资源。
2020

2121
一份 `agents.yaml` 定义 Agent 的环境、模型、指令、工具、技能、MCP、Vault 和凭据。每次变更都能在 PR 中审查,用 `plan` 预览后再执行,不必在控制台里重复搭建同一个 Agent。
2222

@@ -33,6 +33,8 @@ agents validate && agents plan
3333

3434
[5 分钟快速开始](./docs/getting-started.zh-CN.md) · [查看 Provider 支持](./docs/reference/providers.zh-CN.md) · [浏览可运行示例](./docs/examples.md) · [Roadmap](./ROADMAP.md)
3535

36+
[观看 Playground 演示:切换 Provider,运行同一个 Agent 场景](https://github.com/user-attachments/assets/bf51b8d8-f2ed-464b-bca9-0709fefcc44d)
37+
3638
## 为什么是现在
3739

3840
Agent 正在从个人工具变成企业的数字员工。但企业真正重要的东西 —— Prompt、技能、知识文件、工具和运行配置 —— 现在主要只存在于云厂商控制台里。
@@ -45,6 +47,10 @@ OpenAgentPack 在 Agent 和云平台之间建立一个声明式控制平面。
4547

4648
我们的目标,是让 Agent 成为企业可掌控、可迁移、可传承的数字资产。
4749

50+
<p align="center">
51+
<img src="https://img.alicdn.com/imgextra/i1/O1CN016pw0Ax1KuBXckX0Iz_!!6000000001223-2-tps-1254-1254.png" width="360" alt="OpenAgentPack:一份 agents.yaml 管理多个托管 Agent 平台">
52+
</p>
53+
4854
### 声明与可携带:把 Agent 写成一份图纸
4955

5056
借鉴 Docker 的声明思想,把所有决定 Agent 是什么的东西 —— 模型、指令、工具、技能、环境、文件和凭据引用 —— 收敛到一份 `agents.yaml` 图纸里。这份图纸可以进入 Git、接受 PR 审查、复现 Agent,也可以迁移到不同 Provider。
@@ -68,18 +74,6 @@ OpenAgentPack 在 Agent 和云平台之间建立一个声明式控制平面。
6874
- **依赖自动解析** —— Environment → Skill → Agent 按拓扑序创建;依赖失败会跳过下游,而不是留下半成品状态。
6975
- **Drift 恢复** —— 检测远程配置与声明的漂移并收敛回来。YAML 始终是唯一事实来源。
7076

71-
## 效果演示
72-
73-
### CLI 工作流
74-
75-
![OpenAgentPack CLI 工作流](./packages/sdk/docs/agents.gif)
76-
77-
### 本地 Playground
78-
79-
`agents playground` 会启动本地 WebUI,按需拉取匹配版本的 `@openagentpack/playground`,并自动打开浏览器。可通过 `--provider` 指定 `bailian``qoder``ark``claude`
80-
81-
[观看 Playground 演示视频](https://github.com/user-attachments/assets/bf51b8d8-f2ed-464b-bca9-0709fefcc44d)
82-
8377
## 快速开始
8478

8579
```bash
@@ -90,6 +84,10 @@ agents apply -y # 执行变更
9084
agents destroy # 销毁托管资源
9185
```
9286

87+
运行 `agents playground` 可启动本地 WebUI,并通过 `--provider` 指定 `bailian``qoder``ark``claude`。你可以在同一份声明上切换 Provider、运行真实 Session,并观察工具调用和 Artifact。
88+
89+
[观看 Playground 完整演示](https://github.com/user-attachments/assets/bf51b8d8-f2ed-464b-bca9-0709fefcc44d)
90+
9391
最小配置:
9492

9593
```yaml

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Task-oriented, with steps and verification.
2828
| [Configure an agent](./guides/configure-an-agent.md) | Build an `agents.yaml` from minimal to full stack. |
2929
| [Deploy to Bailian](./guides/deploy-to-bailian.md) | Bailian (Aliyun AgentStudio) setup and notes. |
3030
| [Deploy to Qoder](./guides/deploy-to-qoder.md) | Qoder-specific setup and notes. |
31+
| [Use BYOC environments](./guides/use-byoc-environments.md) | Connect Qoder sessions to administrator-provisioned self-hosted environments and private-network tunnels. |
3132
| [Deploy to Claude](./guides/deploy-to-claude.md) | Claude-specific setup and notes. |
3233
| [Deploy to Volcengine Ark](./guides/deploy-to-ark.md) | Volcengine Ark (Managed Agents) setup and notes. |
3334
| [Use skills](./guides/use-skills.md) | Author and attach reusable capability modules. |
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Use BYOC environments
2+
3+
Use a bring-your-own-cloud (BYOC) environment when an administrator has already provisioned a self-hosted Qoder environment and, optionally, a tunnel to private services. OpenCMA references those resources; it does not own their lifecycle.
4+
5+
## Prerequisites
6+
7+
Ask the environment administrator for:
8+
9+
- an environment ID, such as `env_00xxxx`;
10+
- a tunnel ID, such as `tnl_00xxxx`, when the agent needs access to private services;
11+
- the Qoder credentials needed to manage the agent and start sessions.
12+
13+
Do not commit real IDs, private hostnames, or credentials. Use environment variables for credentials and keep live deployment configurations outside the repository.
14+
15+
## Configure the external resources
16+
17+
Declare the provisioned environment with `environment_id` and `self_hosted`. Declare a tunnel by its existing ID, then reference both from the agent.
18+
19+
```yaml
20+
version: "1"
21+
22+
providers:
23+
qoder:
24+
api_key: ${QODER_PAT}
25+
26+
defaults:
27+
provider: qoder
28+
29+
environments:
30+
byoc-environment:
31+
environment_id: env_00xxxx
32+
config:
33+
type: self_hosted
34+
35+
tunnels:
36+
internal-network:
37+
tunnel_id: tnl_00xxxx
38+
39+
agents:
40+
private-service-assistant:
41+
model: qmodel_latest
42+
instructions: You can use the configured private services.
43+
environment: byoc-environment
44+
tunnel: internal-network
45+
tools:
46+
builtin: [Bash, Read]
47+
```
48+
49+
`tunnel` is supported only for Qoder BYOC sessions and deployments. Omit the entire `tunnels` section and the agent's `tunnel` field when no private-network tunnel is needed.
50+
51+
## Apply and run
52+
53+
Apply the configuration to provision or update managed resources such as the agent. The declared environment and tunnel are only recorded as references.
54+
55+
```bash
56+
agents apply -f agents.yaml
57+
agents session run "Check the private service status" --agent private-service-assistant -f agents.yaml
58+
```
59+
60+
You can override the configured IDs for a one-off session without changing the YAML:
61+
62+
```bash
63+
agents session run "Check the private service status" \
64+
--agent private-service-assistant \
65+
--environment-id env_00xxxx \
66+
--tunnel-id tnl_00xxxx \
67+
-f agents.yaml
68+
```
69+
70+
## Lifecycle and cleanup
71+
72+
When `environment_id` is present, OpenCMA never creates, updates, or remotely deletes that environment. Tunnels are always references and are never managed by OpenCMA.
73+
74+
OpenCMA records external ownership in its local state, and the record is sticky:
75+
76+
- Remove the environment declaration entirely and run `agents apply` or `agents destroy`: only the local state record is removed; the administrator-managed environment remains intact.
77+
- Remove only the `environment_id` line while keeping the environment block: `plan`/`apply` fail with an `plan.environment.ownership_transition` error. Silently converting the reference into a managed resource would let OpenCMA modify — and eventually delete — a remote environment it does not own. To take over management deliberately, release the reference first with `agents state rm environment.<name>` and adopt the remote with `agents state import`.
78+
- Point `environment_id` at a different existing environment: the reference is re-recorded and any deployments using it are updated. If the environment was previously managed by OpenCMA under a different remote ID, `plan` warns that the old remote is no longer tracked.
79+
80+
Deleting an agent, session, vault, or other managed resource still follows its normal lifecycle. Use the provider's administrator tooling to modify or delete BYOC environments and tunnels.
81+
82+
## Deployments and tunnels
83+
84+
A deployment that references the BYOC environment runs in that environment, and changing the referenced `environment_id` value updates the deployment on the next `apply`. Qoder's deployment API currently rejects `tunnel_id`, however, so a declared (or agent-inherited) tunnel is not sent with the deployment: scheduled and triggered runs execute without the tunnel, and `validate`/`plan` emits a `qoder.deployment.tunnel.unsupported` warning. Use sessions for workloads that need private-network MCP access.
85+
86+
## Troubleshooting
87+
88+
| Symptom | Check |
89+
|--------|-------|
90+
| Session cannot reach a private service | Confirm the supplied tunnel ID is enabled for the environment and that the service hostname is reachable from the private network. |
91+
| `Tunnel '...' is not defined in config` | Add the name under `tunnels`, or pass `--tunnel-id` for a one-off session. |
92+
| Tunnel unsupported diagnostic | Ensure the agent or deployment targets Qoder; tunnels are not sent to other providers. |
93+
| Environment cannot be resolved | Verify the administrator-provided `environment_id` and the agent's `environment` reference. |
94+
| `plan.environment.ownership_transition` error | Restore `environment_id`, or release the reference with `agents state rm environment.<name>` before managing the environment with OpenCMA. |
95+
| `qoder.deployment.tunnel.unsupported` warning | Expected: Qoder deployments cannot carry a tunnel today. Use sessions for private-network MCP access. |
96+
97+
For field definitions, see the [configuration reference](../reference/configuration.md).

docs/reference/cli.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Export a provider's remote configuration into a local `agents.yaml`.
7373
| `--provider <name>` | Source provider to sync from. |
7474
| `-o, --out <path>` | Output file (default `agents.synced.yaml`). |
7575
| `--force` | Overwrite the output file if it exists. |
76+
| `--skip-missing-files` | Do not prompt for remote files that cannot be downloaded; omit them from the synced output. |
7677

7778
## `agents migrate`
7879

docs/reference/configuration.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ version: "1"
99
providers: { <name>: <provider-config> }
1010
defaults: { provider: <name> | "all" }
1111
environments: { <name>: EnvironmentDecl }
12+
tunnels: { <name>: TunnelDecl }
1213
vaults: { <name>: VaultDecl }
1314
memory_stores:{ <name>: MemoryStoreDecl }
1415
skills: { <name>: SkillDecl }
@@ -23,6 +24,7 @@ deployments: { <name>: DeploymentDecl }
2324
| `providers` | map | yes | One block per provider; each holds its credentials. |
2425
| `defaults.provider` | string | no | Default target for `plan`/`apply`. `all` targets every declared provider. |
2526
| `environments` | map | no | Cloud runtimes. |
27+
| `tunnels` | map | no | Existing Qoder BYOC tunnels referenced by sessions; OpenCMA does not manage their lifecycle. |
2628
| `vaults` | map | no | Credential stores. |
2729
| `memory_stores` | map | no | Persistent agent context (Qoder, Volcengine Ark). |
2830
| `skills` | map | no | Reusable capability modules. |
@@ -72,23 +74,35 @@ environments:
7274
name: <string> # optional
7375
description: <string> # optional
7476
provider: <string> # optional; pin to one provider
77+
environment_id: <string> # optional; reference an existing provider environment without managing it
7578
config:
76-
type: cloud
79+
type: cloud | self_hosted
7780
networking: { ... }
7881
packages: { ... }
7982
metadata: { <key>: <string> }
8083
```
8184

8285
| Field | Type | Required | Description |
8386
|-------|------|:--------:|-------------|
84-
| `config.type` | `"cloud"` | yes | Environment type. |
87+
| `environment_id` | string | no | Existing environment ID. When present, OpenCMA never creates, updates, or deletes the remote environment. Removing this line later is blocked as an ownership error — release first with `agents state rm` (see [Use BYOC environments](../guides/use-byoc-environments.md)). |
88+
| `config.type` | `"cloud"` \| `"self_hosted"` | yes | Environment type. `self_hosted` is used for Qoder BYOC. |
8589
| `config.networking.type` | `"unrestricted"` \| `"limited"` | no | Network policy. |
8690
| `config.networking.allow_mcp_servers` | boolean | no | Allow outbound MCP. |
8791
| `config.networking.allow_package_managers` | boolean | no | Allow package managers. |
8892
| `config.networking.allowed_hosts` | string[] | no | Allow-list for `limited` networks. |
8993
| `config.packages.apt` \| `pip` \| `npm` \| `cargo` \| `gem` \| `go` | string[] | no | Preinstalled packages. |
9094
| `metadata` | map<string,string> | no | Free-form metadata. |
9195

96+
## Tunnel (Qoder BYOC)
97+
98+
```yaml
99+
tunnels:
100+
internal-network:
101+
tunnel_id: tnl_00xxxx
102+
```
103+
104+
Tunnels are existing Qoder resources allocated by the BYOC administrator. They are passed only when a Qoder session/deployment is created and are never created, updated, or deleted by OpenCMA. See [Use BYOC environments](../guides/use-byoc-environments.md) for a complete setup and lifecycle guide.
105+
92106
## Vault
93107

94108
```yaml
@@ -166,6 +180,7 @@ agents:
166180
model: <string> | { <provider>: <string> }
167181
instructions: <string> | <path>
168182
environment: <string>
183+
tunnel: <string> # optional; Qoder BYOC tunnel name
169184
provider: <string>
170185
tools: { builtin: [...], mcp: [...], permissions: {...} }
171186
mcp_servers: [ { name, type?, url? } ]
@@ -181,6 +196,7 @@ agents:
181196
| `model` | string \| map<provider,string> | yes | Single model or a per-provider map. |
182197
| `instructions` | string | yes | Inline text or a path to a file (resolved relative to the config). |
183198
| `environment` | string | no | Environment name. |
199+
| `tunnel` | string | no | Qoder BYOC tunnel name from `tunnels`; unsupported for other providers. |
184200
| `provider` | string | no | Pin the agent to one provider. |
185201
| `tools.builtin` | string[] | yes (in `tools`) | Lowercase tool names. |
186202
| `tools.permissions` | map<string,`"allow"`\|`"ask"`> | no | Per-tool permission policy. |
@@ -214,6 +230,7 @@ deployments:
214230
agent: <string>
215231
agent_version: <number> # optional
216232
environment: <string> # optional
233+
tunnel: <string> # optional; Qoder BYOC only (see note below)
217234
vaults: [ <string> ]
218235
memory_stores: [ <string> ]
219236
resources: [ DeploymentResource ]
@@ -226,6 +243,8 @@ deployments:
226243

227244
`initial_events` is a discriminated union; `schedule.expression` must be a 5-field cron expression.
228245

246+
> **Deployment `tunnel` caveat:** Qoder's deployment API does not accept `tunnel_id`, so the tunnel is dropped from the deployment payload and server-side runs execute without it (`validate`/`plan` emits a warning). Use sessions for private-network MCP access; see [Use BYOC environments](../guides/use-byoc-environments.md).
247+
229248
### Initial events
230249

231250
| Type | Fields |

packages/cli/src/commands/destroy.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ function stopResourceSpinner(spinner: ReturnType<typeof p.spinner> | undefined,
8787
}
8888

8989
if (result.status === "success") {
90-
if (result.reason === "already_gone") {
90+
if (result.reason === "reference_removed") {
91+
spinner.stop(chalk.green(`✓ ${label} — local reference removed (remote left intact)`));
92+
} else if (result.reason === "already_gone") {
9193
spinner.stop(chalk.yellow(`⊘ ${label} — already deleted remotely, cleaned up state`));
9294
} else if (result.cascaded) {
9395
spinner.stop(chalk.green(`✓ ${label} — destroyed (cascaded)`));

packages/cli/src/commands/models.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ export async function modelsListCommand(options: { file: string; provider?: stri
99
for (const listing of listings) {
1010
const name = listing.provider;
1111
if (!listing.supportsDynamicListing) {
12-
if (!options.json) {
12+
if (options.json) {
13+
process.stdout.write(
14+
`${JSON.stringify({ provider: name, supportsDynamicListing: false, models: [] }, null, 2)}\n`,
15+
);
16+
} else {
1317
console.log(chalk.yellow(`\n Provider '${name}' does not support dynamic model listing.`));
1418
if (name === "claude") {
1519
console.log(chalk.dim(` Claude models are specified directly (e.g. claude-sonnet-4-6, claude-opus-4-6).`));

0 commit comments

Comments
 (0)