Skip to content

Commit 8586a2a

Browse files
authored
support Qoder environment setup scripts (#79)
Change-Id: I6396af78a9ea6408645bfa1cdcabafac0936b323
1 parent 4d74bcc commit 8586a2a

21 files changed

Lines changed: 568 additions & 12 deletions

File tree

docs/guides/configure-an-agent.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,16 @@ environments:
5959
packages:
6060
apt: [git, curl]
6161
npm: [typescript]
62+
setup_script: |
63+
set -euo pipefail
64+
install -d /data/workspace/.openagentpack
65+
test -f /data/workspace/.openagentpack/ready || date -u > /data/workspace/.openagentpack/ready
6266
```
6367

6468
Reference an environment from an agent with `environment: dev`.
6569

70+
Qoder supports `config.setup_script` for both cloud and self-hosted environments. It runs the script with `/bin/bash -lc` after declared packages are installed. The UTF-8 limit is 64 KB and the timeout is 10 minutes; a non-zero exit prevents the Session from starting. The script runs once per sandbox and runs again when that sandbox is rebuilt, so make it idempotent. Do not embed credentials—use vaults or environment-backed secret references. Other providers currently reject `setup_script` rather than silently ignoring it.
71+
6672
## Instructions
6773

6874
`instructions` accepts either an inline string or a path to a file:

docs/guides/configure-an-agent.zh-CN.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ environments:
9595
packages:
9696
apt: [git, curl]
9797
npm: [typescript]
98+
setup_script: |
99+
set -euo pipefail
100+
install -d /data/workspace/.openagentpack
101+
test -f /data/workspace/.openagentpack/ready || date -u > /data/workspace/.openagentpack/ready
98102
metadata:
99103
team: platform
100104
```
@@ -122,6 +126,14 @@ packages:
122126
go: [golang.org/x/tools/gopls@latest]
123127
```
124128

129+
Qoder 请求目前只支持 `apt`、`npm` 和 `pip`。`cargo`、`gem`、`go` 是 Qoder 响应中的保留字段,不能在投向 Qoder 的配置中声明非空值;如有需要,可通过 `setup_script` 安装。
130+
131+
### 启动脚本(Qoder)
132+
133+
Qoder 的 cloud 与 self-hosted Environment 都支持 `config.setup_script`。依赖包安装完成后,脚本会通过 `/bin/bash -lc` 执行;UTF-8 最大 64 KB,超时 10 分钟,非零退出会导致 Session 启动失败。脚本在同一 sandbox 中只执行一次,sandbox 重建后会再次执行,因此必须保持幂等。不要把令牌或密码写入脚本,应使用 Vault 或环境变量引用。其他 Provider 当前会明确拒绝 `setup_script`,不会静默忽略。
134+
135+
受管理的 Qoder `self_hosted` Environment,其 `config` 只能包含 `type` 和可选的 `setup_script`;网络与预装包配置仅适用于 cloud Environment。带 `environment_id` 的外部引用仍不由 OpenAgentPack 修改。
136+
125137
---
126138

127139
## 挂载技能包

docs/guides/deploy-to-qoder.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ environments:
7878
type: cloud
7979
networking:
8080
type: unrestricted
81+
packages:
82+
npm: ["pnpm@9"]
83+
setup_script: |
84+
set -euo pipefail
85+
install -d /data/workspace/.openagentpack
86+
test -f /data/workspace/.openagentpack/ready || printf 'ready\n' > /data/workspace/.openagentpack/ready
8187
8288
agents:
8389
assistant:
@@ -90,6 +96,8 @@ agents:
9096
builtin: [read, glob, grep, web_search, web_fetch]
9197
```
9298

99+
Qoder runs `setup_script` after package installation with `/bin/bash -lc`. Scripts are limited to 64 KB of UTF-8 text and 10 minutes, and a non-zero exit prevents Session startup. Make them idempotent because they run again whenever the sandbox is rebuilt. Use vaults for credentials; never place secrets directly in a script. Qoder package declarations accept `apt`, `npm`, and `pip` only.
100+
93101
## What Qoder uniquely supports
94102

95103
- **Memory stores** — persistent context for an agent. See [`examples/qoder/with-memory/`](../../examples/qoder/with-memory/).

docs/reference/configuration.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ environments:
133133
type: cloud | self_hosted
134134
networking: { ... }
135135
packages: { ... }
136+
setup_script: <string>
136137
metadata: { <key>: <string> }
137138
```
138139

@@ -145,8 +146,13 @@ environments:
145146
| `config.networking.allow_package_managers` | boolean | no | Allow package managers. |
146147
| `config.networking.allowed_hosts` | string[] | no | Allow-list for `limited` networks. |
147148
| `config.packages.apt` \| `pip` \| `npm` \| `cargo` \| `gem` \| `go` | string[] | no | Preinstalled packages. |
149+
| `config.setup_script` | string | no | Sandbox setup script. Qoder runs it with `/bin/bash -lc` after package installation; maximum UTF-8 size is 64 KB. Other providers currently reject this field. |
148150
| `metadata` | map<string,string> | no | Free-form metadata. |
149151

152+
Qoder accepts only `apt`, `npm`, and `pip` in package requests. Its API may return empty `cargo`, `gem`, and `go` arrays as reserved response fields, but declaring non-empty values for them is rejected locally. Setup scripts run while a new sandbox is prepared, time out after 10 minutes, and a non-zero exit prevents the Session from starting. Keep scripts idempotent and use vault-backed credentials instead of embedding secrets.
153+
154+
For a managed Qoder `self_hosted` environment, `config` accepts only `type` and optional `setup_script`; networking and packages belong to cloud environments. External `environment_id` references remain unmanaged.
155+
150156
## Tunnel (Qoder BYOC)
151157

152158
```yaml

examples/qoder/full/agents.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ environments:
3232
packages:
3333
apt: [git, curl]
3434
pip: [requests]
35+
setup_script: |
36+
set -euo pipefail
37+
install -d /data/workspace/.openagentpack
38+
test -f /data/workspace/.openagentpack/ready || printf 'ready\n' > /data/workspace/.openagentpack/ready
3539
metadata:
3640
team: platform
3741

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-08-12
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
## Context
2+
3+
Environment declarations flow through the public TypeScript model and Zod parser, provider-aware validation, provider request mapping, and provider-specific reverse/normalization paths used by sync and drift detection. Qoder now exposes `config.setup_script` for both cloud and self-hosted environments, with a 64 KB UTF-8 limit, but every stage currently drops or rejects it. The same API documentation establishes POST update semantics, whole-config replacement, metadata patching, and a narrower writable package set than the shared model.
4+
5+
## Goals / Non-Goals
6+
7+
**Goals:**
8+
9+
- Make setup scripts converge through create, update, sync, export, and drift detection.
10+
- Fail locally for script-size and Qoder package-manager violations.
11+
- Normalize response-only Qoder defaults without hiding declarative differences.
12+
- Correct update and metadata-deletion behavior without changing BYOC ownership rules.
13+
- Prove the contract with focused automated tests and a disposable live Qoder environment.
14+
15+
**Non-Goals:**
16+
17+
- Execute setup scripts locally or expose their Session-time logs through a new API.
18+
- Add file-path indirection for script content; the declaration remains an inline YAML string.
19+
- Claim setup-script support for providers whose current API contract has not been verified.
20+
- Manage externally referenced environments.
21+
22+
## Decisions
23+
24+
1. Add `setup_script?: string` to the shared environment config, but gate actual use per provider. This keeps the declaration portable while preventing adapters from silently dropping unsupported behavior. A Qoder-only extension object was considered, but would make the common Environment model needlessly provider-shaped.
25+
2. Enforce the documented maximum with `Buffer.byteLength(value, "utf8")`, not JavaScript string length, because the remote limit is byte-oriented and scripts may contain non-ASCII content.
26+
3. Keep the shared package union for other providers, while Qoder validation rejects non-empty `cargo`, `gem`, and `go`. Qoder normalization retains only writable `apt`, `npm`, and `pip` values and removes empty response defaults plus `packages.type`.
27+
4. Include setup scripts in both reverse mapping and comparable normalization. Absence and an empty string remain distinct because clearing a saved script must be representable and reconciled.
28+
5. Change Qoder environment update to POST and construct metadata tombstones from the current remote object before updating. This matches Qoder's metadata patch semantics while still sending the complete desired config.
29+
6. Exercise live behavior with a uniquely named disposable environment loaded from `.env`, verify create/get/update/readback, then delete it in a `finally` cleanup path. No secret or `.env` content is printed.
30+
31+
## Risks / Trade-offs
32+
33+
- [Provider documentation changes again] → Keep Qoder-specific validation and normalization isolated and back it with request-contract tests.
34+
- [A live setup script can cause Session startup failure] → Use a harmless marker script in live testing and document idempotency, failure, and secret-handling guidance.
35+
- [Metadata tombstones could target management metadata] → Diff only non-`agents.*` remote metadata and continue injecting management metadata normally.
36+
- [Empty arrays from Qoder cause false drift] → Canonicalize package objects on both desired and remote sides before hashing.
37+
- [Live cleanup fails] → Print only the disposable resource ID/name and an explicit cleanup command, leaving credentials undisclosed.
38+
39+
## Migration Plan
40+
41+
The field is optional, so existing declarations retain their current hashes after normalization. Deploy the parser, validation, mapper, adapter, tests, and documentation together. Rollback is code-only; environments already containing scripts continue to exist remotely, though an older client would no longer manage that field.
42+
43+
## Open Questions
44+
45+
None. The current Qoder documentation is explicit about accepted fields, execution semantics, and update behavior.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
## Why
2+
3+
OpenAgentPack cannot currently declare Qoder's `config.setup_script`, so environment initialization that cannot be expressed as packages is lost across create, update, sync, and drift reconciliation. The Qoder Environment adapter also diverges from the current API contract for updates and accepted package managers, making otherwise valid plans fail late or reconcile indefinitely.
4+
5+
## What Changes
6+
7+
- Add portable environment `setup_script` declarations with local UTF-8 64 KB validation.
8+
- Support Qoder setup scripts across create, update, remote readback, sync/export, and drift comparison for cloud and self-hosted environments.
9+
- Align Qoder Environment updates with the documented POST endpoint and full-config replacement behavior.
10+
- Reject Qoder package-manager declarations that the API exposes only as response placeholders (`cargo`, `gem`, and `go`).
11+
- Normalize Qoder response-only package fields and empty defaults so they do not create false drift.
12+
- Make Qoder environment metadata deletion converge when a declared key is removed.
13+
- Document execution semantics, failure behavior, security guidance, and examples in English and Chinese.
14+
15+
## Capabilities
16+
17+
### New Capabilities
18+
19+
- `environment-setup-script`: Declarative environment setup scripts, provider capability validation, lifecycle reconciliation, and user-facing execution semantics.
20+
21+
### Modified Capabilities
22+
23+
None.
24+
25+
## Impact
26+
27+
This affects the SDK environment configuration types and parser, provider validation, Qoder environment mapper and adapter, sync/drift behavior, Qoder-focused tests and fixtures, configuration documentation, environment guides, and Qoder examples. It does not introduce new runtime dependencies or change external-resource ownership semantics.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
## ADDED Requirements
2+
3+
### Requirement: Declare an environment setup script
4+
The system SHALL accept an optional inline `config.setup_script` string for an Environment and SHALL reject scripts whose UTF-8 representation exceeds 65,536 bytes.
5+
6+
#### Scenario: Valid multiline script
7+
- **WHEN** a cloud or self-hosted Environment declares a multiline setup script within the byte limit
8+
- **THEN** configuration parsing succeeds and preserves the script exactly
9+
10+
#### Scenario: Oversized Unicode script
11+
- **WHEN** an Environment setup script exceeds 65,536 UTF-8 bytes
12+
- **THEN** validation fails locally before any provider request is made
13+
14+
### Requirement: Enforce provider setup-script support
15+
The system SHALL send setup scripts only to providers that support them and SHALL report an actionable validation error for managed environments targeting an unsupported provider.
16+
17+
#### Scenario: Qoder managed environment
18+
- **WHEN** a managed Qoder cloud or self-hosted Environment declares a setup script
19+
- **THEN** the script is included in the provider Environment config
20+
21+
#### Scenario: Unsupported provider
22+
- **WHEN** a managed Environment targeting another provider declares a setup script
23+
- **THEN** validation reports that the provider does not support environment setup scripts
24+
25+
#### Scenario: External environment reference
26+
- **WHEN** an externally managed Environment declaration contains a provider ID
27+
- **THEN** OpenAgentPack does not attempt to mutate that Environment
28+
29+
### Requirement: Reconcile Qoder setup scripts
30+
The system SHALL preserve Qoder setup scripts through create, update, remote readback, sync/export, and drift comparison.
31+
32+
#### Scenario: Script changes
33+
- **WHEN** a declared setup script differs from the current Qoder Environment
34+
- **THEN** planning reports an Environment update and applying it sends the complete desired config
35+
36+
#### Scenario: Script converges
37+
- **WHEN** the remote Qoder Environment contains the declared setup script
38+
- **THEN** subsequent planning reports no setup-script drift
39+
40+
#### Scenario: Script removal
41+
- **WHEN** a previously configured setup script is removed from the declaration
42+
- **THEN** the Qoder Environment is updated so future Sessions no longer execute it
43+
44+
### Requirement: Follow the Qoder Environment API contract
45+
The system SHALL update Qoder Environments with the documented POST operation, SHALL converge metadata deletions, and SHALL reject writable package declarations not accepted by Qoder.
46+
47+
#### Scenario: Environment update
48+
- **WHEN** an owned Qoder Environment changes
49+
- **THEN** OpenAgentPack sends POST to the Environment resource with a complete config
50+
51+
#### Scenario: Metadata key removed
52+
- **WHEN** a user metadata key previously present remotely is removed from the declaration
53+
- **THEN** the update sends a null tombstone for that key and preserves management metadata
54+
55+
#### Scenario: Unsupported Qoder package manager
56+
- **WHEN** a Qoder Environment declares a non-empty `cargo`, `gem`, or `go` package list
57+
- **THEN** validation fails before apply with an actionable diagnostic
58+
59+
#### Scenario: Response defaults
60+
- **WHEN** Qoder returns response-only package type fields, reserved package arrays, or empty writable arrays
61+
- **THEN** normalization omits them from comparison unless they correspond to a declared writable package value
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
## 1. Configuration contract
2+
3+
- [x] 1.1 Add `setup_script` to the environment type and parser with a UTF-8 64 KB limit
4+
- [x] 1.2 Add provider-aware validation for setup-script support and Qoder writable package managers
5+
6+
## 2. Qoder reconciliation
7+
8+
- [x] 2.1 Map and reverse-map setup scripts and canonicalize Qoder package responses
9+
- [x] 2.2 Include setup scripts in Qoder desired/remote comparable state and drift detection
10+
- [x] 2.3 Correct Qoder Environment updates to POST and converge removed metadata keys
11+
12+
## 3. Verification coverage
13+
14+
- [x] 3.1 Add parser and provider validation boundary tests
15+
- [x] 3.2 Add Qoder Environment create/update, sync, normalization, and drift regression tests
16+
- [x] 3.3 Update the live drift fixture to cover setup scripts and response-only package fields
17+
18+
## 4. Documentation
19+
20+
- [x] 4.1 Update English and Chinese configuration/environment documentation with setup-script semantics and safety guidance
21+
- [x] 4.2 Add a Qoder example using an idempotent multiline setup script
22+
23+
## 5. Delivery verification
24+
25+
- [x] 5.1 Run focused tests, SDK typecheck, scoped verification, and the full SDK suite
26+
- [x] 5.2 Review the complete diff and fix all actionable findings
27+
- [x] 5.3 Load `.env` and verify disposable Qoder Environment create, update, readback/drift, and cleanup against the live API

0 commit comments

Comments
 (0)