@desplega.ai/agent-env 0.3.0 → 0.4.0

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/README.md CHANGED
@@ -20,6 +20,27 @@ npm install -g @desplega.ai/agent-env
20
20
 
21
21
  For a source checkout, run `npm link --ignore-scripts --no-audit --no-fund` in this repository instead.
22
22
 
23
+ Read the bundled [agent skill](https://github.com/desplega-ai/agent-env/blob/master/skills/agent-env/SKILL.md) or install it into a project:
24
+
25
+ ```sh
26
+ agent-env skill
27
+ agent-env skill install
28
+ agent-env skill install --agent codex --yes
29
+ ```
30
+
31
+ `skill` prints the complete guide offline. Add `--json` for structured output.
32
+ `skill install` runs the skills installer with files bundled in your CLI version.
33
+ To install the latest guide directly from GitHub instead:
34
+
35
+ ```sh
36
+ npx skills add desplega-ai/agent-env --skill agent-env
37
+ ```
38
+
39
+ The skills installer requires Node.js 22.20 or later and lets you choose your coding agents.
40
+ Add `--agent codex` or `--agent claude-code` to select one explicitly.
41
+ Add `-g` for installation across projects. The skill teaches CLI usage and does not install the CLI or Docker.
42
+ It covers local services, Compose, dotenv, SSH, HTTPS, persistent data, and troubleshooting.
43
+
23
44
  ```sh
24
45
  cd /path/to/project
25
46
  agent-env init
package/bin/agent-env.mjs CHANGED
@@ -12,10 +12,12 @@ import { initialize } from '../src/init.mjs';
12
12
  import { addService } from '../src/goodies.mjs';
13
13
  import { setEnvironmentSecret, listEnvironmentSecrets, unsetEnvironmentSecret } from '../src/environments.mjs';
14
14
  import { delay } from '../src/system.mjs';
15
+ import { skillCommand } from '../src/skill.mjs';
15
16
 
16
17
  const help = `agent-env: development services with stable localhost addresses
17
18
 
18
19
  agent-env init Create agent-env.json
20
+ agent-env skill [install] Read or install the bundled agent skill
19
21
  agent-env add postgres | redis Add a persistent service
20
22
  agent-env up [--ssh user@host] Start the configured stack
21
23
  agent-env up NAME Resume the saved instance from any directory
@@ -125,6 +127,7 @@ async function main() {
125
127
  const separator = args.indexOf('--');
126
128
  const command = separator < 0 ? [] : args.splice(separator).slice(1);
127
129
  const { values, positionals } = parseArgs({ args, allowPositionals: true, options: {
130
+ agent: { type: 'string', multiple: true }, global: { type: 'boolean', short: 'g' }, yes: { type: 'boolean', short: 'y' },
128
131
  'env-file': { type: 'string', multiple: true }, 'no-env-file': { type: 'boolean' }, 'from-env': { type: 'string' },
129
132
  version: { type: 'boolean', short: 'v' },
130
133
  timeout: { type: 'string' },
@@ -143,6 +146,7 @@ async function main() {
143
146
  console.log(values.json ? JSON.stringify({ version }) : version);
144
147
  return;
145
148
  }
149
+ if (type === 'skill') { await skillCommand(positionals.slice(1), values, command); return; }
146
150
  if (!type || values.help || type === 'help') { console.log(help); return; }
147
151
  if (type === 'trust') { display(await trustTls(), values.json); return; }
148
152
  if (type === 'add') { display(await addService(name, { config: values.config, port: values.port, environment: values.env }), values.json); return; }
package/docs/releases.md CHANGED
@@ -19,12 +19,15 @@ The `CI` job requires all these jobs to succeed:
19
19
 
20
20
  | Job | Runtime | Real dependencies |
21
21
  | --- | --- | --- |
22
- | Core | Linux and macOS, Node 22 and latest LTS | Git, public CLI |
22
+ | Core | Linux and macOS, Node 22 and latest LTS | Git, npm, public skills installer, public CLI |
23
23
  | Docker | Linux, latest Node LTS | Docker, HTTP, TCP, TLS, sandbox bridge |
24
24
  | Compose | Linux, latest Node LTS | Docker Compose |
25
25
  | SSH | Linux, latest Node LTS | Dedicated localhost sshd, Docker, Compose, rsync |
26
26
  | S3 | Linux, latest Node LTS | Docker Compose, AWS CLI, disposable SeaweedFS |
27
27
 
28
+ Core tests install the bundled skill with the real skills installer into a temporary project.
29
+ They verify Codex and Claude Code files and remove the isolated npm cache afterward.
30
+
28
31
  The SSH fixture generates new client and host keys for every job.
29
32
  The client pins the generated host key and requires strict host verification.
30
33
  The fixture starts its own sshd with password authentication disabled.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/agent-env",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Run development services behind stable localhost addresses.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -29,6 +29,7 @@
29
29
  "files": [
30
30
  "bin",
31
31
  "src",
32
+ "skills",
32
33
  "README.md",
33
34
  "LICENSE",
34
35
  "examples",
@@ -0,0 +1,156 @@
1
+ ---
2
+ name: agent-env
3
+ description: Run and troubleshoot development environments with agent-env, including Docker, Compose, dotenv, SSH, local routing, and persistent data.
4
+ license: MIT
5
+ ---
6
+
7
+ # agent-env
8
+
9
+ Use the `agent-env` CLI to run development services behind stable localhost addresses.
10
+ These instructions describe CLI version 0.4.0.
11
+ Check `agent-env --help` when the installed version differs from these instructions.
12
+ Run `agent-env skill` to read this guide and its reference offline.
13
+ Run `agent-env skill install` to install the bundled skill for your coding agent.
14
+
15
+ ## Prepare the project
16
+
17
+ 1. Inspect `agent-env.json`, Compose files, and package scripts before changing configuration.
18
+ 2. Check `agent-env --version`. If absent, install the CLI with `npm install -g @desplega.ai/agent-env`.
19
+ 3. Check `docker info`. Compose projects also require `docker compose version`.
20
+ 4. Inspect `agent-env --json list` before choosing an instance name or reusing ports.
21
+
22
+ The CLI requires macOS or Linux and Node.js 22 or later.
23
+ Installing this skill does not install the CLI or Docker.
24
+ Preserve existing project configuration and the user's selected compute target.
25
+ Use local Docker when no remote target is requested.
26
+
27
+ ## Start and verify
28
+
29
+ Existing Compose files work directly with `up`.
30
+ For another project without `agent-env.json`, run `agent-env init` to detect its development command.
31
+ Do not overwrite an existing configuration.
32
+ If detection fails, supply the actual project command, image, and port. For example:
33
+
34
+ ```sh
35
+ agent-env init --image node:22-bookworm-slim --port 3000 -- node server.js
36
+ ```
37
+
38
+ Replace `node server.js` with the project's command.
39
+ Native services run in `/workspace`, which contains the checkout.
40
+ Include dependency installation in the command when needed.
41
+ The server must listen on `0.0.0.0` inside its container.
42
+
43
+ ```sh
44
+ agent-env up --name app --local
45
+ agent-env --json list
46
+ agent-env logs app --service web
47
+ agent-env exec app --service web -- node --version
48
+ agent-env ui
49
+ ```
50
+
51
+ Replace `app` and `web` with the chosen instance and service names.
52
+ Choose an exec command supported by the service's image.
53
+ Use returned addresses instead of assuming port 3000.
54
+ Verify a real application response through the returned HTTP URL.
55
+ For PostgreSQL or another TCP service, verify a connection with its native client.
56
+ Report the instance, target, service URLs, verification result, and any remaining failure.
57
+
58
+ `app.localhost:PORT` addresses one HTTP instance.
59
+ `agent-env use app` selects the instance behind bare `localhost:PORT` and raw TCP ports.
60
+ Changing selection closes existing connections through bare localhost.
61
+ The local daemon must remain running for routing and SSH tunnels.
62
+
63
+ ## Compose and configuration
64
+
65
+ ```sh
66
+ agent-env up --name app --local --compose-file compose.yaml --profile tools
67
+ ```
68
+
69
+ Use only files and profiles that the project defines.
70
+ Repeat `--compose-file` or `--profile` for multiple entries.
71
+ Compose retains builds, health checks, dependencies, named volumes, and internal services.
72
+ Keep secrets in declared `environment`, `env_file`, or Compose secret sources.
73
+ Use `compose.routes` when one service needs aliases for multiple published ports.
74
+ See the [Compose configuration examples](https://github.com/desplega-ai/agent-env/blob/master/examples/compose/README.md).
75
+
76
+ For a Vite project using native Docker, define `services` in `agent-env.json`:
77
+
78
+ ```json
79
+ {
80
+ "services": {
81
+ "web": {
82
+ "image": "node:22-bookworm-slim",
83
+ "port": 3000,
84
+ "containerPort": 3000,
85
+ "command": "npm ci && npm run dev -- --host 0.0.0.0 --port 3000",
86
+ "volumes": { "dependencies": "/workspace/node_modules" }
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ Adapt the command to the project. Named volumes retain dependencies and application data.
93
+ Use `agent-env add postgres` or `agent-env add redis` to generate a persistent service configuration.
94
+ For a named environment, include `--env review` when adding its service.
95
+
96
+ ## Dotenv and private values
97
+
98
+ Automatic file order is `.env`, `.env.local`, `.env.<name>`, then `.env.<name>.local`.
99
+ The last two files apply when `--env NAME` selects a named environment.
100
+ Example files do not load automatically.
101
+
102
+ ```sh
103
+ agent-env up --name review --local --env review
104
+ agent-env up --name app --local --env-file .env.development
105
+ agent-env up --name app --local --no-env-file
106
+ agent-env env set API_TOKEN --from-env MY_API_TOKEN
107
+ agent-env env list
108
+ ```
109
+
110
+ Choose one dotenv selection method. `--env-file` replaces automatic selection and conflicts with `--no-env-file`.
111
+ Do not print dotenv contents or secret values.
112
+ Private values can also enter through stdin: `agent-env env set API_TOKEN < /path/to/private/token-file`.
113
+ Use `--env NAME` consistently for the secret store and startup.
114
+ Stores belong to the current project and selected environment.
115
+
116
+ Native Docker treats dotenv values literally. It does not expand shell expressions.
117
+ The parent shell enters native containers only through explicit `{ "env": "NAME" }` references.
118
+ Compose retains shell interpolation precedence. Its services must declare container variables through `environment` or `env_file`.
119
+ `--no-env-file` does not disable Compose service `env_file` declarations.
120
+ See [environment precedence and secret references](https://github.com/desplega-ai/agent-env/blob/master/README.md#environments-and-secrets) for detailed configuration.
121
+
122
+ Saved instances retain resolved values:
123
+
124
+ - `agent-env up app` resumes saved configuration from any directory.
125
+ - `agent-env up --name app` reads the current project's configuration and reloads edited dotenv files.
126
+ - Environment-only changes recreate Docker or Compose containers and preserve named volumes.
127
+ - Structural changes, such as ports or commands, require `rm app`, then `up --name app` with the intended target.
128
+
129
+ Do not use `rm --purge` to resolve a configuration mismatch. It deletes managed data.
130
+
131
+ ## Stop and troubleshoot
132
+
133
+ Use `agent-env down app` to stop services and retain data.
134
+ `agent-env rm app` removes containers but retains volumes and built images.
135
+ `agent-env rm app --purge` also removes managed data and owned Compose image tags.
136
+ Delete data only when that deletion is part of the user's request.
137
+ `agent-env daemon stop` stops routing and synchronization, but leaves containers running.
138
+ Avoid `--all` when working on one project.
139
+
140
+ | Symptom | Next action |
141
+ | --- | --- |
142
+ | Startup timeout | Inspect `logs`. Check the bind address, port, and health check. Increase `--timeout` for slow initialization. |
143
+ | Old environment values | Run `up --name NAME` from the correct checkout with the intended environment and dotenv options. |
144
+ | Configuration changed | Inspect the change. Use `rm NAME`, then recreate without `--purge` to retain data. |
145
+ | Port conflict | Inspect `list` and the port owner. Change configuration instead of terminating unrelated processes. |
146
+ | Stale remote files | Run `sync NAME`. Check exclusions before expecting credentials or generated directories to transfer. |
147
+ | CLI request timed out | Check `list` and `logs` before retrying. The daemon may still be starting services. |
148
+
149
+ For a slow saved instance, use `agent-env up app --timeout 900`.
150
+ Startup timeouts accept 1 to 3600 seconds. Compose image builds precede the readiness timeout.
151
+
152
+ ## Additional workflows
153
+
154
+ Read [remote services and data operations](references/remote-and-data.md) for SSH, Hetzner, HTTPS, snapshots, and worktree forks.
155
+ For Agent Swarm itself, follow the [tested example](https://github.com/desplega-ai/agent-env/blob/master/docs/agent-swarm.md).
156
+ That example uses an explicit private env file, isolated Linux dependencies, and a 900-second startup timeout.
@@ -0,0 +1,140 @@
1
+ # Remote services and data operations
2
+
3
+ Read only the section needed for the requested operation.
4
+ Keep existing authorization for the selected host and data operation.
5
+ This skill does not authorize paid infrastructure, trust changes, or data deletion by itself.
6
+
7
+ ## Existing SSH hosts
8
+
9
+ The local machine needs SSH and rsync.
10
+ The remote host needs Docker, rsync, Bash, and `timeout`. Compose projects also need Docker Compose.
11
+ Use an SSH alias or `--ssh-config FILE` for credentials and ports.
12
+ Establish and verify the host key through the normal SSH workflow. Do not disable host verification.
13
+
14
+ ```sh
15
+ agent-env up --name remote --ssh dev-host
16
+ agent-env --json list
17
+ agent-env sync remote
18
+ agent-env logs remote --service web
19
+ agent-env down remote
20
+ agent-env up remote
21
+ ```
22
+
23
+ Replace `dev-host` with the authorized SSH alias or `user@host`.
24
+ Remote source synchronization follows local edits unless startup includes `--no-watch`.
25
+ The daemon reconnects failed SSH tunnels automatically.
26
+ Verify the returned localhost address after startup and after a representative source edit.
27
+
28
+ Sync excludes `.git`, `node_modules`, `.agent-env`, `.env*`, and common generated directories.
29
+ Root `build` and `dist` directories are excluded. Nested source paths such as `src/build` still transfer.
30
+ Keep other credentials outside the checkout.
31
+ Remote Compose bind mounts, build contexts, and Dockerfiles must remain inside the checkout and pass the sync exclusions.
32
+ Compose secret files use a separate private transfer.
33
+
34
+ ## Owned Hetzner machines
35
+
36
+ Use this workflow only when the user requests paid infrastructure.
37
+ Check the authenticated `hcloud` context before provisioning.
38
+
39
+ ```sh
40
+ agent-env up --name cloud --cloud hetzner --location hel1
41
+ agent-env down cloud
42
+ agent-env up cloud
43
+ ```
44
+
45
+ `down` powers off the owned machine when no other running instance needs it.
46
+ Powered-off machines still incur charges.
47
+ `agent-env rm cloud --purge` deletes the last instance's owned machine, IP, key, and data.
48
+ Forks share the source machine. Removing one instance preserves its peers.
49
+ Keep the original hcloud context and credential for lifecycle operations.
50
+ If either changes, the CLI refuses access and preserves recovery records.
51
+ Do not delete those records to bypass an error.
52
+
53
+ The default idle timeout is 30 minutes. `--idle-minutes 0` disables it.
54
+ `--ttl-hours N` sets a destructive expiry for the shared machine and all its instances, including sleeping forks.
55
+ Idle shutdown and expiry require the local daemon to remain running and connected.
56
+ These are not cloud-side schedules. Do not promise cost control after the daemon stops.
57
+
58
+ ## HTTPS and the dashboard
59
+
60
+ ```sh
61
+ agent-env up --name app --local --https --https-port 8443
62
+ agent-env ui --port 4780
63
+ ```
64
+
65
+ Read the actual HTTPS URLs from `agent-env list`.
66
+ The primary HTTP service uses `https://app.localhost:8443`.
67
+ Other HTTP services use `https://app--SERVICE.localhost:8443`.
68
+ The dashboard shows status and recent redacted logs. It accepts local read-only requests.
69
+
70
+ `agent-env trust` installs the local certificate authority into the OS trust store.
71
+ Run it only when trust installation is authorized. Linux installation requires sudo.
72
+ Certificate creation during `up --https` does not install OS trust.
73
+ For verification without a trust change, use the generated CA:
74
+
75
+ ```sh
76
+ curl --cacert ~/.local/state/agent-env/tls/ca.pem \
77
+ --resolve app.localhost:8443:127.0.0.1 https://app.localhost:8443/
78
+ ```
79
+
80
+ Use `$AGENT_ENV_HOME/tls/ca.pem` instead when the state directory was overridden.
81
+ Some browsers and runtimes use separate certificate stores.
82
+
83
+ ## Forks
84
+
85
+ Stop the source before copying database volumes:
86
+
87
+ ```sh
88
+ agent-env down app
89
+ agent-env fork app experiment --worktree ../experiment --branch experiment
90
+ agent-env --json list
91
+ ```
92
+
93
+ This creates a Git worktree, copies source changes and volumes, and starts an independent fork.
94
+ Credentials and generated files are excluded from copied source changes.
95
+ Without worktree options, `fork app experiment` copies data and reuses the source checkout.
96
+ Forks require a new destination name and use the source Docker host.
97
+ Verify that a database write in the fork does not change the source data.
98
+ Resume a saved fork with `agent-env up experiment`, even from another directory.
99
+
100
+ Instance removal retains worktrees by default.
101
+ `rm NAME --remove-worktree` removes an owned clean worktree.
102
+ `--discard-worktree` also permits removal of changed and ignored files. Use it only for an authorized discard.
103
+
104
+ ## Snapshots and restore
105
+
106
+ ```sh
107
+ agent-env down app
108
+ agent-env snapshot app /existing/backups/checkpoint
109
+ agent-env restore /existing/backups/checkpoint --name restored
110
+ ```
111
+
112
+ Run restore from the intended project checkout with the intended environment options.
113
+ Restore uses current project configuration and creates fresh volumes before startup.
114
+ It verifies archive checksums and refuses existing destination volumes.
115
+ Snapshots contain volume data, not source files or a complete deployable project.
116
+ Unsupported or shared mounts cause an error. Do not add `--omit-mounts` unless the user accepts the missing data.
117
+
118
+ S3 uses the installed AWS CLI and its configured credentials:
119
+
120
+ ```sh
121
+ agent-env snapshot app s3://my-bucket/checkpoint
122
+ agent-env restore s3://my-bucket/checkpoint --name restored --ssh dev-host
123
+ ```
124
+
125
+ Use a new snapshot prefix. `--endpoint URL` selects compatible object storage.
126
+ S3 stores backups. Running databases still use Docker volumes.
127
+ Snapshots need temporary local disk space. AWS S3 exports are limited to 5 GB per volume.
128
+ For format and ownership details, read the [snapshot documentation](https://github.com/desplega-ai/agent-env/blob/master/docs/snapshots-and-worktrees.md).
129
+
130
+ ## Provider and state boundaries
131
+
132
+ State defaults to `~/.local/state/agent-env`. `AGENT_ENV_HOME` selects another private directory.
133
+ State can contain environment values and cloud ownership credentials. Do not publish it or treat it as disposable cache.
134
+ For isolated tests, set `AGENT_ENV_HOME` before the first CLI command.
135
+ Remove only the test's resources, then stop its daemon before deleting its state.
136
+
137
+ The sandbox bridge is available through `--provider sandbox --adapter docker`.
138
+ Custom sandbox adapters are trusted local ESM modules.
139
+ Firecracker and hosted sandbox vendor integrations are not bundled.
140
+ See the [adapter contract](https://github.com/desplega-ai/agent-env/blob/master/src/providers/CLOUD_SANDBOX.md) before proposing a new provider.
package/src/skill.mjs ADDED
@@ -0,0 +1,51 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const directory = new URL('../skills/agent-env/', import.meta.url);
6
+ const help = `agent-env skill: instructions for coding agents
7
+
8
+ agent-env skill Print the bundled guide and reference
9
+ agent-env skill --json Print the guide as JSON
10
+ agent-env skill install Install the bundled skill into this project
11
+ agent-env skill install --agent codex --yes
12
+ agent-env skill install --agent claude-code --global
13
+
14
+ Install options:
15
+ --agent NAME Select an agent (repeat for multiple agents)
16
+ -g, --global Install across projects
17
+ -y, --yes Accept the skills installer's prompts
18
+
19
+ Reading needs no network, Docker, or daemon.
20
+ Installation runs npx skills@1.7.6 and requires Node 22.20+ and npm.
21
+ The installer uses the skill files bundled with this CLI version.
22
+ `;
23
+
24
+ export async function skillCommand(positionals, values, command) {
25
+ if (values.help) { console.log(help); return; }
26
+ const [action] = positionals;
27
+ if (positionals.length > 1 || command.length || action && action !== 'install') {
28
+ throw new Error('Use agent-env skill or agent-env skill install.');
29
+ }
30
+ const allowed = action ? ['agent', 'global', 'yes'] : ['json'];
31
+ for (const key of Object.keys(values)) {
32
+ if (!allowed.includes(key)) throw new Error(`Option --${key} is not supported here. Run agent-env skill --help.`);
33
+ }
34
+ if (!action) {
35
+ const guide = await readFile(new URL('SKILL.md', directory), 'utf8');
36
+ const reference = await readFile(new URL('references/remote-and-data.md', directory), 'utf8');
37
+ const content = `${guide.replace('(references/remote-and-data.md)', '(#remote-services-and-data-operations)')}\n${reference}`;
38
+ if (values.json) console.log(JSON.stringify({ name: 'agent-env', content }, null, 2));
39
+ else process.stdout.write(content);
40
+ return;
41
+ }
42
+ const args = ['--yes', 'skills@1.7.6', 'add', fileURLToPath(directory), '--skill', 'agent-env'];
43
+ for (const agent of values.agent ?? []) args.push('--agent', agent);
44
+ if (values.global) args.push('--global');
45
+ if (values.yes) args.push('--yes');
46
+ process.exitCode = await new Promise((resolve, reject) => {
47
+ const child = spawn('npx', args, { stdio: 'inherit' });
48
+ child.once('error', error => reject(new Error(`Cannot start npx: ${error.message}. Install npm, then retry.`)));
49
+ child.once('close', code => resolve(code ?? 1));
50
+ });
51
+ }