Agent Sandbox Registry

agent-sandbox

Repository Layout Review: the cli repository

无中文版

docs/design/repository-layout.md

Repository Layout Review: the cli repository

Status: recommendation (architecture review, 2026-10-12). Maintainer-facing, English only. This is the CLI-relevant copy; the full review (Python packaging, python-sdk layout, shared decisions) is docs/en/design/repository-layout.md in python-sdk. The two copies are not kept byte-identical; shared decisions are summarised here so this repo is self-contained.

0. Verdict

  1. cli is its own repository (github.com/alibaba-agent-sandbox/agent-sandbox, npm @agent-sandbox/cli, bin abx), versioned independently of the Python SDK. First npm release is 0.3.0.
  2. Keep the current src/ tree until the parity gate, then re-home it once (one mechanical commit) to src/{bin,cli,core,agent,providers,pyparity}. Moving earlier breaks the ledger (tests/<python path>) and the porting traceability that docs/PORTING.md promises; moving never would ship a layout that only makes sense to someone holding the Python tree.
  3. No npm workspace now. One published package. Introduce packages/provider-api (@agent-sandbox/provider-api, types + defineProvider) when the provider plugin contract is frozen; keep core an internal directory guarded by a lint rule.
  4. Docs: the CLI owns CLI pages only. Contract pages (template.yaml spec, error-code taxonomy, server HTTP API) are owned by python-sdk and linked by absolute URL. No page may exist byte-identically in both repos.
  5. .agents/ gets its own README.md, four ADRs move to python-sdk, cross-repo references become absolute URLs, evidence/research stay tracked and scrubbed of personal paths.
  6. Publish the Node tree as one commit on top of the existing agent-sandbox/agent-sandbox history (tags kept), no umbrella monorepo; the SDK goes to the new agent-sandbox/python-sdk repository.
  7. scripts/check-repo-health.sh encodes the definition of done; run it as the required repo-health CI check.

1. What exists today (measured)

Fact Evidence
src/ = models utils transport protocol api session agent cli/commands framework mirroring the Python tree, 1351-entry parity ledger keyed by tests/<python path> docs/PORTING.md, parity/
framework/ is not a CLI framework in the Node sense: it holds Python-stdlib/click emulation (difflib.ts, py.ts, exceptions.ts, formatting.ts); seven more Python-emulation helpers are scattered over modules: agent/_py.ts, agent/_pycompat.ts, api/_pyerrors.ts, api/_shlex.ts, utils/_pyformat.ts, utils/_pypath.ts, models/_pydantic.ts src/
package.json bin points at dist/bin/abx.js but src/bin/abx.ts did not exist at review time package.json, src/
No .gitignore; node_modules is a symlink into /tmp/parity; no package-lock.json; devDependencies (typescript, vitest, @types/node) and, at review time, runtime deps yaml/smol-toml/ws/@inquirer/prompts missing from package.json: a fresh clone cannot build cli/
repository.url points at the old agent-sandbox repo; no homepage, bugs, publishConfig.access (a scoped package defaults to restricted) package.json
.github has community files but no workflows/; dependabot.yml still lists pip .github/
Python leftovers: benchmarks/bench_cli_startup.py, scripts/{build_hermes,deploy_all_templates,deploy_remaining}.sh call agent_sandbox.cli / .venv/bin/python with a hard-coded /Users/anycodes/...Qoder... path; tests/_fuzz_tmp.test.ts was a scratch file at review time benchmarks/, scripts/, tests/
docs/PORTING.md cites /tmp/agent-sandbox, /tmp/venv-orig, "this VM" (not publishable as is) file
The evidence README documents a generator (scripts/capture_cli_evidence.py) that no longer exists in either repo .agents/evidence/README.md
15 broken relative links, 16 dangling ADR/evidence slugs (ADRs now living in python-sdk), doc pages that link SDK-only pages (sdk-usage.md, declarative-usage.md, design/architecture.md, reference/api-reference.md) health script
npm view: unscoped abx is taken by a third party; @agent-sandbox/cli is unpublished; npm scope ownership unverified npm registry

2. Decision C - TypeScript layout

2.1 Is the mirrored tree sensible for an npm CLI?

For the port: yes. As the public layout: no, for four reasons: (1) cli/commands nests the product's core concept two levels deep and cli sits next to SDK-ish siblings; (2) the SDK-like core (transport, protocol, api, models) has no boundary, so commands can reach into anything; (3) Python-emulation shims (_py*, framework) are mixed with product code and cannot be found or deleted as a group; (4) file names keep Python's snake_case (session_manager.ts) while Node convention is kebab-case.

2.2 Options

1. Keep mirror forever 2. Re-home once after the gate (recommended) 3. npm workspace now (packages/core, packages/cli, providers)
Traceability to Python during the port perfect perfect until the gate, then via parity/ledger-map.json needs a package-boundary decision before the code settles
Public readability / contributor onboarding poor good good
Provider plugin support needs a place for providers/ anyway core/provider (contract) + providers/ (builtin) clean (provider-api package)
Migration cost / risk none / none one codemod commit, tests must be green before and after (pure rename risk) high now (publishing 3 packages, version coordination)
Verdict rejected recommended deferred until a second consumer exists

Triggers to move from 2 to 3: a third-party provider plugin needs types (publish @agent-sandbox/provider-api first, as the only extra workspace package), or a TypeScript SDK is requested (extract @agent-sandbox/core). Moving later is a git mv plus CI path changes; it is cheap, so do not pre-pay.

2.3 Target tree (after the parity gate)

src/
├── bin/abx.ts                 # entry; built to dist/bin/abx.js (shebang preserved by tsc)
├── cli/
│   ├── main.ts  output.ts     # program, global flags, OutputManager
│   ├── commands/              # one file per command group (config, deploy, mcp, sandbox*, template, provider)
│   └── framework/             # command parsing / help rendering (from src/framework)
├── core/                      # SDK-like, no imports from cli/ or agent/ (ESLint no-restricted-imports)
│   ├── models/ transport/ protocol/ api/ session/ utils/
│   └── provider/              # provider interface, registry, plugin loader
├── agent/                     # MCP server, coding-agent integration, template authoring/adoption
├── providers/alicloud/        # builtin default provider (from api/fc_template, docker_builder bits)
└── pyparity/                  # every _py*/_pyerrors/_pyformat/_pypath/_pydantic/_shlex/difflib shim

Rules: file names kebab-case (ESLint unicorn/filename-case); core is import-isolated; pyparity is the only place allowed to emulate Python behaviour and is deleted as parity tests stop needing it; provider plugins are loaded dynamically (abx provider install <path|git>) and import only @agent-sandbox/provider-api.

2.4 Tests

3. Decision B (CLI part) - docs, examples, scripts

Area Decision
README root README.md + README.zh-CN.md: install (npm i -g @agent-sandbox/cli, binary), quick start, command overview, docs map, link to python-sdk (SDK, server runtime)
Docs one tree docs/{en,zh}/{guide,reference,design}; CLI-owned pages: cli-tutorial, cli-reference, cli-design, binary-installation, agent-skill-installation, using-templates, deploy-and-build, e2e-template-workflow, templates-catalog, plus its own trimmed getting-started, authentication, environment-variables, troubleshooting, configuration, mcp-integration, authoring-templates. Add guide/providers.md (install, use, author), guide/contributing-code.md. docs/design/repository-layout.md (this file) is English-only maintainer documentation
Owned elsewhere (link, never copy) reference/template-yaml-spec, reference/error-codes (taxonomy; keep CLI-specific codes such as E2007 and the exit-code map), reference/server-http-api, design/server-api, SDK pages (sdk-usage, declarative-usage, api-reference, architecture)
Examples examples/: CLI recipes, CI usage (--ci --json), a provider-plugin skeleton
Scripts / benchmarks scripts/ = repo tooling only (parity-coverage.mjs, check-repo-health.sh, build_binary.mjs); maintainer E2E deployment scripts go to .agents/ops/ without personal paths; benchmarks/startup.mjs replaces the Python benchmark
Shared tooling .githooks + .secrets.baseline (copies are fine), ESLint + Prettier + .editorconfig + .nvmrc; no Python pre-commit config
CI ci.yml: npm ci, typecheck, lint, unit tests on Node 20/22 x Linux/macOS/Windows, parity:coverage until the gate, pack smoke test (npm pack -> install -> abx --version), repo-health; release.yml: tag vX.Y.Z -> npm publish --provenance --access public (OIDC); release-binary.yml: Node SEA binaries attached to the GitHub Release; docs-links.yml: scheduled lychee
Dependabot npm (root) + github-actions; remove pip

4. Decision D (CLI part) - .agents/

5. Decision E - publishing

agent-sandbox/agent-sandbox (existing docs and issue forms already use it; abx would also be a fine repo name but would touch every cross-link), npm @agent-sandbox/cli, bin abx, later @agent-sandbox/provider-api. Cross-repo links are absolute https://github.com/alibaba-agent-sandbox/python-sdk/blob/main/... URLs (CHANGELOG uses tag-pinned URLs); never ../python-sdk. The health script rejects relative links that leave the repo.

7. Ordered move plan (CLI)

Legend: NOW = new files or files no builder owns; COORD = small edit to a shared file; LATER = after the builders finish; WAIT = after the parity gate.

# Step When
C1 add .gitignore (node_modules, dist, coverage, parity/.vitest-report.json), .editorconfig, .nvmrc, eslint.config.js, .agents/README.md, .github/workflows/{ci,release,docs-links}.yml, .github/CODEOWNERS, scripts/check-repo-health.sh (done) NOW
C2 dependabot.yml: pip -> npm COORD
C3 remove/rewrite Python leftovers (benchmark, three shell scripts), remove tests/_fuzz_tmp.test.ts NOW (tests file: LATER, builders own tests/)
C4 docs/PORTING.md: drop /tmp/... and "this VM", cite commit b15b88f NOW
C5 .agents: README, ADR moves/supersede, scrub, absolute cross-repo URLs, ADR 2026-10-12-cli-repository-layout NOW
C6 package.json completion + package-lock.json + real node_modules COORD
C7 docs ownership sweep, SDK-page links to absolute URLs, guide/providers.md, guide/contributing-code.md, examples/ LATER
C8 keep the mirrored src/ and tests/; new code only in new directories (src/providers/, src/core/provider/) until the gate
C9 one mechanical commit: git mv src/{models,transport,protocol,api,session,utils} src/core/; git mv src/framework src/cli/framework; shims -> src/pyparity/; kebab-case renames; codemod imports; ESLint isolation rule; tests re-homed; parity/ledger-map.json; archive parity/ + PORTING.md WAIT (post-gate, builders frozen)
C10 health script green with --strict; publish (section 5) LATER (final)

8. Definition of done (cli)

9. scripts/check-repo-health.sh

Read-only; --strict makes WARN fail; --quiet prints only problems. Uses bash + node (>= 20). Checks: top-level files, README/CHANGELOG headings, .github + CI semantics (npm vs pip, npm ci, npm publish, provenance), package.json completeness and undeclared imports, symlinked node_modules, .gitignore, Python leftovers, stale scripts, docs (en/zh parity, required pages, examples/), .agents (README, ADR rules), content hygiene (broken relative links, links leaving the repo, leaked local paths, dangling ADR slugs, stale "coming soon", pages byte-identical with ../python-sdk).

Results (the builders kept writing during the review, so the numbers moved; re-run for the live state): first run PASS 67 / WARN 13 / FAIL 25 (no .gitignore, no ci.yml, package.json metadata and devDependencies, node_modules symlink, Python leftovers, leaked paths in 10 files); latest run PASS 83 / WARN 13 / FAIL 12: no release.yml; repository/homepage/bugs/publishConfig.access; no src/bin/abx.ts; no examples/; no .agents/README.md; 14 broken links; /Users/... paths left in 2 .agents evidence files; 16 dangling ADR slugs; template-yaml-spec byte-identical with python-sdk. Expected end state: exit 0 with --strict.