agentme 0.3.3 → 0.6.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/.xdrs/agentme/edrs/application/003-javascript-project-tooling.md +32 -11
- package/.xdrs/agentme/edrs/application/010-golang-project-tooling.md +32 -18
- package/.xdrs/agentme/edrs/application/014-python-project-tooling.md +152 -0
- package/.xdrs/agentme/edrs/application/015-cli-tool-standards.md +107 -0
- package/.xdrs/agentme/edrs/application/skills/001-create-javascript-project/SKILL.md +61 -19
- package/.xdrs/agentme/edrs/application/skills/003-create-golang-project/SKILL.md +19 -9
- package/.xdrs/agentme/edrs/application/skills/005-create-python-project/SKILL.md +363 -0
- package/.xdrs/agentme/edrs/devops/005-monorepo-structure.md +37 -5
- package/.xdrs/agentme/edrs/devops/006-github-pipelines.md +6 -1
- package/.xdrs/agentme/edrs/devops/008-common-targets.md +5 -0
- package/.xdrs/agentme/edrs/devops/skills/002-monorepo-setup/SKILL.md +58 -12
- package/.xdrs/agentme/edrs/governance/013-contributing-guide-requirements.md +5 -0
- package/.xdrs/agentme/edrs/index.md +3 -0
- package/.xdrs/agentme/edrs/observability/011-service-health-check-endpoint.md +5 -0
- package/.xdrs/agentme/edrs/principles/002-coding-best-practices.md +5 -0
- package/.xdrs/agentme/edrs/principles/004-unit-test-requirements.md +5 -0
- package/.xdrs/agentme/edrs/principles/007-project-quality-standards.md +7 -2
- package/.xdrs/agentme/edrs/principles/009-error-handling.md +5 -0
- package/.xdrs/agentme/edrs/principles/012-continuous-xdr-enrichment.md +6 -1
- package/.xdrs/agentme/edrs/principles/016-cross-language-module-structure.md +133 -0
- package/.xdrs/agentme/edrs/principles/articles/001-continuous-xdr-improvement.md +3 -3
- package/package.json +23 -3
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentme-edr-003-javascript-project-tooling-and-structure
|
|
3
|
+
description: Defines the standard JavaScript and TypeScript project toolchain and layout using Mise, pnpm, TypeScript, ESLint, Jest, and Makefiles. Use when scaffolding or reviewing JavaScript projects.
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# agentme-edr-003: JavaScript project tooling and structure
|
|
2
7
|
|
|
3
8
|
## Context and Problem Statement
|
|
@@ -8,7 +13,7 @@ What tooling and project structure should JavaScript/TypeScript projects follow
|
|
|
8
13
|
|
|
9
14
|
## Decision Outcome
|
|
10
15
|
|
|
11
|
-
**Use a Mise-managed Node.js and pnpm toolchain together with pnpm, tsc, esbuild, eslint, and jest in a
|
|
16
|
+
**Use a Mise-managed Node.js and pnpm toolchain together with pnpm, tsc, esbuild, eslint, and jest in a module-root layout that follows [agentme-edr-016](../principles/016-cross-language-module-structure.md), with runnable usage examples in sibling `examples/` folders and Makefiles as the only entry points.**
|
|
12
17
|
|
|
13
18
|
Clear, consistent tooling and layout enable fast onboarding, reliable CI pipelines, and a predictable developer experience across projects.
|
|
14
19
|
|
|
@@ -42,29 +47,39 @@ When `tsconfig.json` extends `@tsconfig/node24/tsconfig.json`, the default `modu
|
|
|
42
47
|
#### Project structure
|
|
43
48
|
|
|
44
49
|
```
|
|
45
|
-
/ # workspace root
|
|
50
|
+
/ # workspace root or parent aggregation root
|
|
46
51
|
├── .mise.toml # pinned Node.js and pnpm versions
|
|
52
|
+
├── .gitignore # MUST ignore dist/ and .cache/
|
|
47
53
|
├── Makefile # delegates build/lint/test to /lib and /examples
|
|
48
|
-
├── README.md #
|
|
49
|
-
├── lib/ #
|
|
54
|
+
├── README.md # workspace overview and quickstart
|
|
55
|
+
├── lib/ # one JavaScript/TypeScript module root
|
|
50
56
|
│ ├── Makefile # build, lint, test, publish targets
|
|
57
|
+
│ ├── README.md # package README used for publishing
|
|
51
58
|
│ ├── package.json # package manifest
|
|
52
59
|
│ ├── tsconfig.json # TypeScript config for build and linting
|
|
53
60
|
│ ├── jest.config.js # Jest config
|
|
54
61
|
│ ├── eslint.config.mjs # ESLint config (ESLint 9 flat config)
|
|
62
|
+
│ ├── .cache/ # eslint, jest, tsc incremental state, coverage
|
|
63
|
+
│ ├── dist/ # compiled files and packed .tgz artifacts
|
|
55
64
|
│ └── src/ # all TypeScript source files
|
|
56
65
|
│ ├── index.ts # public API re-exports
|
|
57
66
|
│ └── *.test.ts # test files co-located with source
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
├── examples/ # runnable usage examples outside the module root
|
|
68
|
+
│ ├── Makefile # build + test all examples in sequence
|
|
69
|
+
│ ├── usage-x/ # first example
|
|
70
|
+
│ │ └── package.json
|
|
71
|
+
│ └── usage-y/ # second example
|
|
72
|
+
│ └── package.json
|
|
73
|
+
├── tests_integration/ # optional cross-example or cross-module integration tests
|
|
74
|
+
└── tests_benchmark/ # optional benchmark harnesses
|
|
64
75
|
```
|
|
65
76
|
|
|
66
77
|
The root `Makefile` delegates every target to `/lib` then `/examples` in sequence and is expected to execute module commands inside the repository's Mise-managed environment.
|
|
67
78
|
|
|
79
|
+
When a repository contains multiple JavaScript/TypeScript packages, each package MUST live in its own module folder such as `lib/my-package/` or `services/my-service/`, each with its own `Makefile`, `README.md`, `dist/`, and `.cache/`.
|
|
80
|
+
|
|
81
|
+
Persistent caches MUST live under `.cache/`. Recommended locations are Jest `cacheDirectory`, ESLint `--cache-location`, TypeScript `tsBuildInfoFile`, and coverage outputs.
|
|
82
|
+
|
|
68
83
|
The commands below assume they are invoked through `mise exec -- make <target>` or from an activated Mise shell.
|
|
69
84
|
|
|
70
85
|
#### lib/Makefile targets
|
|
@@ -78,7 +93,7 @@ The commands below assume they are invoked through `mise exec -- make <target>`
|
|
|
78
93
|
| `lint-fix` | `pnpm exec eslint ./src --fix` |
|
|
79
94
|
| `test` | `pnpm exec jest --verbose` |
|
|
80
95
|
| `test-watch` | `pnpm exec jest --watch` |
|
|
81
|
-
| `clean` | remove `node_modules
|
|
96
|
+
| `clean` | remove `node_modules/`, `dist/`, and `.cache/` |
|
|
82
97
|
| `all` | `build lint test` |
|
|
83
98
|
| `publish` | version-bump with `monotag`, then `npm publish --provenance` |
|
|
84
99
|
|
|
@@ -93,6 +108,12 @@ The commands below assume they are invoked through `mise exec -- make <target>`
|
|
|
93
108
|
|
|
94
109
|
Each sub-folder under `examples/` is an independent package. The Makefile installs the locally built `.tgz` pack from `lib/dist/` so examples simulate real external usage.
|
|
95
110
|
|
|
111
|
+
Examples MUST remain outside the module root and MUST consume the package through the packed artifact in `dist/`, never through `../src` imports or other direct source links.
|
|
112
|
+
|
|
113
|
+
Module-specific integration tests that are not just runnable examples belong in `lib/tests_integration/` or a sibling `tests_integration/` when they cover multiple modules.
|
|
114
|
+
|
|
115
|
+
Benchmarks belong in `lib/tests_benchmark/` when they require dedicated harnesses; simple micro-benchmarks may stay co-located only if the local testing stack makes that idiomatic.
|
|
116
|
+
|
|
96
117
|
The examples folder MUST exist for any libraries and utilities that are published or have more than 500 lines of code
|
|
97
118
|
|
|
98
119
|
### Related Skills
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentme-edr-010-go-project-tooling-and-structure
|
|
3
|
+
description: Defines the standard Go project toolchain, layout, and Makefile workflow for agentme-based projects. Use when scaffolding or reviewing Go projects.
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# agentme-edr-010: Go project tooling and structure
|
|
2
7
|
|
|
3
8
|
## Context and Problem Statement
|
|
@@ -8,7 +13,7 @@ What tooling and project structure should Go projects follow to ensure consisten
|
|
|
8
13
|
|
|
9
14
|
## Decision Outcome
|
|
10
15
|
|
|
11
|
-
**Use the standard Go toolchain (`go build`, `go test`) with `golangci-lint
|
|
16
|
+
**Use the standard Go toolchain (`go build`, `go test`) with `golangci-lint`, module-root folder responsibilities from [agentme-edr-016](../principles/016-cross-language-module-structure.md), feature packages in subdirectories, a `cli/` package for command wiring, and a Makefile as the single entry point for all development tasks.**
|
|
12
17
|
|
|
13
18
|
A predictable layout and minimal external tooling keep Go projects approachable, fast to build, and easy to distribute as cross-platform binaries.
|
|
14
19
|
|
|
@@ -29,33 +34,40 @@ Direct installation of project-required Go CLIs with `go install ...@latest` as
|
|
|
29
34
|
#### Project structure
|
|
30
35
|
|
|
31
36
|
```
|
|
32
|
-
/ # project root
|
|
37
|
+
/ # project root or Go module root inside a monorepo
|
|
33
38
|
├── Makefile # build, lint, test, publish, and utility targets
|
|
39
|
+
├── README.md # module README with usage and development commands
|
|
40
|
+
├── .gitignore # MUST ignore dist/ and .cache/
|
|
41
|
+
├── .golangci.yml # golangci-lint configuration
|
|
34
42
|
├── go.mod # module declaration (github.com/<owner>/<project>)
|
|
35
43
|
├── go.sum # locked dependency checksums
|
|
36
44
|
├── main.go # binary entry point — argument dispatch only, no logic
|
|
37
|
-
├── .
|
|
38
|
-
├──
|
|
39
|
-
├── README.md
|
|
45
|
+
├── .cache/ # GOCACHE, GOMODCACHE, golangci-lint cache, coverage
|
|
46
|
+
├── dist/ # built binaries and packaged outputs
|
|
40
47
|
├── <feature-a>/ # domain package (e.g. ownership/, changes/, utils/)
|
|
41
48
|
│ ├── *.go # business logic
|
|
42
49
|
│ └── *_test.go # unit tests co-located with source
|
|
43
50
|
├── <feature-b>/
|
|
44
51
|
│ └── ...
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
├── cli/ # CLI wiring — ties flags to domain packages
|
|
53
|
+
│ ├── <feature-a>/
|
|
54
|
+
│ │ └── *.go
|
|
55
|
+
│ └── <feature-b>/
|
|
56
|
+
│ └── *.go
|
|
57
|
+
├── tests_integration/ # optional integration tests for this module
|
|
58
|
+
├── tests_benchmark/ # optional benchmark harnesses and datasets
|
|
59
|
+
└── examples/ # optional sibling consumer examples for libraries
|
|
50
60
|
```
|
|
51
61
|
|
|
52
62
|
**Key layout rules:**
|
|
53
63
|
|
|
54
64
|
- One Go module per project (`go.mod` at the project root). In a monorepo, each Go project has its own `go.mod` in its subdirectory. No nested modules within a single project unless explicitly justified.
|
|
65
|
+
- In a multi-module repository, each Go module MUST live in its own folder root with its own `Makefile`, `README.md`, `dist/`, and `.cache/`.
|
|
55
66
|
- `main.go` is solely an argument dispatcher — it reads `os.Args[1]` and delegates to a `cli/<feature>/Run*()` function. No domain logic lives in `main.go`.
|
|
56
67
|
- Business logic lives in named feature packages at the root (e.g., `ownership/`, `changes/`, `utils/`). These packages are importable and testable without any CLI concerns.
|
|
57
68
|
- `cli/` packages own flag parsing, output formatting, and the wiring between flags and domain functions. No business logic lives in `cli/`.
|
|
58
69
|
- Packages are flat by default; sub-packages are only introduced when a feature package itself exceeds ~400 lines or has clearly separable sub-concerns.
|
|
70
|
+
- Consumer examples for reusable libraries belong in a sibling `examples/` folder and MUST import the public module path rather than reaching into internal source paths. Because Go libraries are not typically consumed from a local packaged artifact, local example validation may use a temporary module replacement for resolution, but the import path MUST remain the public module path.
|
|
59
71
|
|
|
60
72
|
#### go.mod
|
|
61
73
|
|
|
@@ -69,16 +81,16 @@ Direct installation of project-required Go CLIs with `go install ...@latest` as
|
|
|
69
81
|
| Target | Description |
|
|
70
82
|
|--------|-------------|
|
|
71
83
|
| `all` | Default; runs `build lint test` in sequence |
|
|
72
|
-
| `build` | `go mod download && go build -o dist/<binary>` |
|
|
84
|
+
| `build` | `go mod download && go build -o dist/<binary>` with Go caches redirected into `.cache/` |
|
|
73
85
|
| `build-all` | Cross-compile for all target platforms (darwin/linux/windows × amd64/arm64) |
|
|
74
86
|
| `build-arch-os` | Compile for a specific `OS` and `ARCH` environment variable pair; output to `dist/${OS}-${ARCH}/<binary>` |
|
|
75
87
|
| `install` | `go mod download` |
|
|
76
|
-
| `lint` | `golangci-lint run ./...` |
|
|
77
|
-
| `lint-fix` | `golangci-lint run --fix ./...` |
|
|
78
|
-
| `test` | `go test -cover ./...` — runs all tests with coverage |
|
|
88
|
+
| `lint` | `golangci-lint run ./...` with its cache redirected into `.cache/` |
|
|
89
|
+
| `lint-fix` | `golangci-lint run --fix ./...` with its cache redirected into `.cache/` |
|
|
90
|
+
| `test` | `go test -cover ./...` — runs all tests with coverage and stores disposable outputs under `.cache/` |
|
|
79
91
|
| `test-unit` | `go test -cover ./...` — alias for unit tests only (same here; integration tests get a separate tag) |
|
|
80
|
-
| `coverage` | `go tool cover -func
|
|
81
|
-
| `clean` | Remove `dist/` and
|
|
92
|
+
| `coverage` | `go tool cover -func .cache/coverage.out` — displays coverage summary |
|
|
93
|
+
| `clean` | Remove `dist/` and `.cache/` |
|
|
82
94
|
| `start` | `go run ./ <default-args>` — launch the binary locally for dev use |
|
|
83
95
|
| `publish` | Tag with `monotag`, then push tag + binaries to GitHub Releases |
|
|
84
96
|
|
|
@@ -107,8 +119,10 @@ When the project produces a CLI binary for end-users:
|
|
|
107
119
|
- Tests are co-located with source: `<feature>/<file>_test.go`.
|
|
108
120
|
- Use `github.com/stretchr/testify` (`assert`, `require`) for test assertions.
|
|
109
121
|
- Run all tests: `go test -cover ./...`
|
|
110
|
-
- Benchmarks: `
|
|
111
|
-
- Integration or slow tests: guard with `//go:build integration` and
|
|
122
|
+
- Benchmarks: keep simple `Benchmark*` functions co-located in `*_test.go`; use `tests_benchmark/` when the benchmark needs dedicated harnesses or datasets.
|
|
123
|
+
- Integration or slow tests: guard with `//go:build integration` and keep them in `tests_integration/` when they are not naturally co-located with one package.
|
|
124
|
+
|
|
125
|
+
Redirect Go tool caches into `.cache/` using `GOCACHE`, `GOMODCACHE`, and `GOLANGCI_LINT_CACHE` from the module `Makefile` so the repository does not accumulate scattered cache directories.
|
|
112
126
|
|
|
113
127
|
#### Linting
|
|
114
128
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentme-edr-014-python-project-tooling-and-structure
|
|
3
|
+
description: Defines the standard Python project toolchain, layout, and Makefile workflow using uv, ruff, pyright, pytest, and pip-audit. Use when scaffolding or reviewing Python projects.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# agentme-edr-014: Python project tooling and structure
|
|
7
|
+
|
|
8
|
+
## Context and Problem Statement
|
|
9
|
+
|
|
10
|
+
Python projects often drift into mixed dependency managers, duplicated configuration files, and ad hoc quality checks, which makes onboarding and CI pipelines inconsistent.
|
|
11
|
+
|
|
12
|
+
What tooling and project structure should Python projects follow to ensure consistency, quality, and ease of development?
|
|
13
|
+
|
|
14
|
+
## Decision Outcome
|
|
15
|
+
|
|
16
|
+
**Use a uv-managed Python project with `pyproject.toml`, `ruff`, `pyright`, `pytest`, `pytest-cov`, `pip-audit`, and a layout that follows [agentme-edr-016](../principles/016-cross-language-module-structure.md): a module root under `lib/`, runnable consumer examples in sibling `examples/`, and standardized `dist/` and `.cache/` locations.**
|
|
17
|
+
|
|
18
|
+
A single dependency manager, isolated package internals under `lib/`, and a standard Makefile contract keep Python projects predictable for contributors and CI while keeping the repository root clean.
|
|
19
|
+
|
|
20
|
+
### Implementation Details
|
|
21
|
+
|
|
22
|
+
#### Tooling
|
|
23
|
+
|
|
24
|
+
| Tool | Purpose |
|
|
25
|
+
|------|---------|
|
|
26
|
+
| **uv** | Dependency management, lockfile management, virtualenv sync, build, publish |
|
|
27
|
+
| **pyproject.toml** | Single source of truth for package metadata and tool configuration |
|
|
28
|
+
| **ruff** | Formatting, import sorting, linting, and common code-quality checks |
|
|
29
|
+
| **pyright** | Static type checking |
|
|
30
|
+
| **pytest** | Test runner |
|
|
31
|
+
| **pytest-cov** | Coverage reporting and threshold enforcement |
|
|
32
|
+
| **pip-audit** | Dependency CVE audit |
|
|
33
|
+
|
|
34
|
+
All routine commands must run through the project `Makefile`, never by calling `uv`, `ruff`, `pytest`, or `pyright` directly in docs, CI, or daily development workflows.
|
|
35
|
+
|
|
36
|
+
When the repository defines a root `.mise.toml`, Python and uv must be pinned there and commands should run through `mise exec --` or an activated Mise shell.
|
|
37
|
+
|
|
38
|
+
The root `.venv/` is the canonical environment location for both the library and all examples. Subdirectory commands must set `UV_PROJECT_ENVIRONMENT` to the workspace root `.venv/` instead of creating nested virtual environments.
|
|
39
|
+
|
|
40
|
+
Persistent caches must live under `.cache/`, preferably the module `lib/.cache/` plus a shared root `.cache/uv/` when uv cache sharing is desired.
|
|
41
|
+
|
|
42
|
+
#### Project structure
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
/
|
|
46
|
+
├── .mise.toml # optional but required when the repo uses Mise
|
|
47
|
+
├── .gitignore
|
|
48
|
+
├── .cache/ # optional shared uv cache at repo level
|
|
49
|
+
├── .venv/ # shared uv environment for lib/ and examples/
|
|
50
|
+
├── Makefile # root entry point; delegates to lib/ and runs examples/
|
|
51
|
+
├── README.md # workspace/repository overview
|
|
52
|
+
├── lib/ # everything the published library needs
|
|
53
|
+
│ ├── Makefile # build, lint, test, publish targets for the library
|
|
54
|
+
│ ├── pyproject.toml # package metadata + tool config
|
|
55
|
+
│ ├── uv.lock # committed lockfile for the library
|
|
56
|
+
│ ├── README.md # package README used for publishing
|
|
57
|
+
│ ├── .cache/ # pytest, Ruff, coverage, Python bytecode cache
|
|
58
|
+
│ ├── src/
|
|
59
|
+
│ │ └── <package_name>/
|
|
60
|
+
│ │ ├── __init__.py
|
|
61
|
+
│ │ ├── __main__.py # when the project exposes a CLI
|
|
62
|
+
│ │ └── ...
|
|
63
|
+
│ ├── tests/
|
|
64
|
+
│ │ ├── conftest.py # shared fixtures when needed
|
|
65
|
+
│ │ └── test_*.py
|
|
66
|
+
│ ├── tests_integration/ # optional integration tests for this module
|
|
67
|
+
│ ├── tests_benchmark/ # optional benchmark harnesses and datasets
|
|
68
|
+
│ └── dist/ # wheels / sdists built from lib/
|
|
69
|
+
└── examples/ # independent consumer projects
|
|
70
|
+
├── example1/
|
|
71
|
+
│ ├── pyproject.toml
|
|
72
|
+
│ └── main.py
|
|
73
|
+
└── example2/
|
|
74
|
+
├── pyproject.toml
|
|
75
|
+
└── main.py
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Keep the repository root clean: source code, tests, distribution artifacts, and package metadata live under `lib/`, while the root contains only orchestration and repository-level files.
|
|
79
|
+
|
|
80
|
+
Use the `lib/src/` layout for import safety and packaging clarity. Keep tests under `lib/tests/` and shared test setup in `lib/tests/conftest.py`. Do not introduce `requirements.txt`, `setup.py`, `setup.cfg`, `tox.ini`, `ruff.toml`, or `pyrightconfig.json` by default; keep project metadata and tool configuration in `lib/pyproject.toml`.
|
|
81
|
+
|
|
82
|
+
Libraries and shared utilities must include an `examples/` folder and wire example execution into the root `test` flow, following [agentme-edr-007](../principles/007-project-quality-standards.md). Each example directory is its own Python project with its own `pyproject.toml`, and examples must import the library as a consumer would rather than reaching back into `lib/src/` with relative imports. Local example verification must install the wheel built into `lib/dist/`; do not use editable or path-based dependencies back to `lib/`.
|
|
83
|
+
|
|
84
|
+
Python keeps unit tests under `lib/tests/` by default because that remains the more common and maintainable convention for typed/package-based projects than co-locating tests beside every source file. Integration tests belong in `lib/tests_integration/`, and benchmark harnesses belong in `lib/tests_benchmark/` when they are more than a single micro-benchmark helper.
|
|
85
|
+
|
|
86
|
+
#### `lib/pyproject.toml`
|
|
87
|
+
|
|
88
|
+
- Runtime dependencies belong in `[project.dependencies]`.
|
|
89
|
+
- Development-only tooling belongs in `[dependency-groups].dev`.
|
|
90
|
+
- Configure Ruff, Pyright, and Pytest in `lib/pyproject.toml` under their `tool.*` sections.
|
|
91
|
+
- Commit `lib/uv.lock` and keep it in sync with `lib/pyproject.toml`.
|
|
92
|
+
- Expose CLI entry points with `[project.scripts]` when the project provides commands.
|
|
93
|
+
|
|
94
|
+
When Pyright runs from `lib/`, configure it to discover the shared root virtual environment, for example with `venvPath = ".."` and `venv = ".venv"`.
|
|
95
|
+
|
|
96
|
+
Ruff is the default formatter and linter. Do not add Black, isort, or Flake8 unless another XDR for that repository explicitly requires them.
|
|
97
|
+
|
|
98
|
+
Pyright must run on every lint pass. `typeCheckingMode = "standard"` is the minimum baseline; projects may raise this to `strict` when the codebase is ready.
|
|
99
|
+
|
|
100
|
+
Pytest coverage must fail below 80% line and branch coverage, following [agentme-edr-004](../principles/004-unit-test-requirements.md).
|
|
101
|
+
|
|
102
|
+
#### Makefile targets
|
|
103
|
+
|
|
104
|
+
The commands below assume invocation through `mise exec -- make <target>` when the repository uses Mise, or plain `make <target>` inside an activated project environment.
|
|
105
|
+
|
|
106
|
+
#### Root `Makefile`
|
|
107
|
+
|
|
108
|
+
The root `Makefile` is the only contract for CI and contributors. It delegates library work to `lib/` and runs each example project in `examples/` against the shared root `.venv/`.
|
|
109
|
+
|
|
110
|
+
| Target | Description |
|
|
111
|
+
|--------|-------------|
|
|
112
|
+
| `install` | Run `lib/install` to create or update the shared root `.venv/` |
|
|
113
|
+
| `build` | Run `lib/build` |
|
|
114
|
+
| `lint` | Run `lib/lint` |
|
|
115
|
+
| `lint-fix` | Run `lib/lint-fix` |
|
|
116
|
+
| `test-unit` | Run `lib/test-unit` |
|
|
117
|
+
| `test-examples` | For each `examples/*/pyproject.toml`, sync and run the example serially against the shared root `.venv/` |
|
|
118
|
+
| `test` | Run `test-unit`, then `test-examples` when applicable |
|
|
119
|
+
| `clean` | Remove the shared root `.venv/`, root `.cache/`, and delegate cleanup to `lib/` |
|
|
120
|
+
| `all` | `build lint test` |
|
|
121
|
+
|
|
122
|
+
#### `lib/Makefile`
|
|
123
|
+
|
|
124
|
+
| Target | Description |
|
|
125
|
+
|--------|-------------|
|
|
126
|
+
| `install` | `uv sync --project . --frozen --all-extras --dev` using the shared root `.venv/` |
|
|
127
|
+
| `build` | `uv sync --project . --frozen --all-extras --dev && uv build --project . --out-dir dist` |
|
|
128
|
+
| `lint` | `uv run --project . ruff format --check . && uv run --project . ruff check . && uv run --project . pyright && uv run --project . pip-audit`, with caches redirected into `.cache/` |
|
|
129
|
+
| `lint-fix` | `uv run --project . ruff format . && uv run --project . ruff check . --fix && uv run --project . pyright && uv run --project . pip-audit`, with caches redirected into `.cache/` |
|
|
130
|
+
| `test-unit` | `uv run --project . pytest --cov=src/<package_name> --cov-branch --cov-report=term-missing --cov-fail-under=80`, with pytest and coverage outputs stored under `.cache/` |
|
|
131
|
+
| `clean` | Remove `dist/` and `.cache/` inside `lib/` |
|
|
132
|
+
| `all` | `build lint test-unit` |
|
|
133
|
+
| `update-lockfile` | `uv lock --project . --upgrade` |
|
|
134
|
+
| `run` | `uv run --project . python -m <package_name>` or the project CLI entry point |
|
|
135
|
+
| `dev` | Same as `run`, optionally with repository-specific dev defaults |
|
|
136
|
+
| `publish` | `uv publish --project .` after versioning and packaging are complete |
|
|
137
|
+
|
|
138
|
+
The root `Makefile` must remain the only contract for CI and contributors, in line with [agentme-edr-008](../devops/008-common-targets.md).
|
|
139
|
+
|
|
140
|
+
## Considered Options
|
|
141
|
+
|
|
142
|
+
* (REJECTED) **Mixed Python tooling** - Separate tools and config files such as `pip`, `requirements.txt`, `setup.cfg`, `flake8`, and `mypy`.
|
|
143
|
+
* Reason: Increases cognitive load, duplicates configuration, and weakens the standard command surface across projects.
|
|
144
|
+
* (CHOSEN) **uv + `lib/` package layout + Ruff/Pyright/Pytest toolchain** - One dependency manager, package internals isolated under `lib/`, consumer examples under `examples/`, and one root Makefile contract.
|
|
145
|
+
* Reason: Keeps packaging, dependency locking, static analysis, security auditing, and test execution consistent while aligning Python repositories with the established JavaScript layout.
|
|
146
|
+
|
|
147
|
+
## References
|
|
148
|
+
|
|
149
|
+
- [agentme-edr-004](../principles/004-unit-test-requirements.md) - Coverage and unit-test baseline
|
|
150
|
+
- [agentme-edr-007](../principles/007-project-quality-standards.md) - Examples and quality requirements
|
|
151
|
+
- [agentme-edr-008](../devops/008-common-targets.md) - Standard Makefile target names
|
|
152
|
+
- [005-create-python-project](skills/005-create-python-project/SKILL.md) - Scaffold a project following this EDR
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentme-edr-015-cli-tool-standards
|
|
3
|
+
description: Defines how distributable CLI tools should separate command handling from library logic and expose consistent command behavior. Use when designing or reviewing CLI interfaces.
|
|
4
|
+
applied-to: Distributable CLI tools and their standalone libraries
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# agentme-edr-015: CLI tool standards
|
|
8
|
+
|
|
9
|
+
## Context and Problem Statement
|
|
10
|
+
|
|
11
|
+
CLI projects often mix command parsing, business logic, config loading, and output formatting in one entry point, making them hard to reuse as libraries and inconsistent to operate.
|
|
12
|
+
|
|
13
|
+
What structure and interface rules should distributable CLI tools follow so they remain discoverable, scriptable, and reusable outside the command line?
|
|
14
|
+
|
|
15
|
+
## Decision Outcome
|
|
16
|
+
|
|
17
|
+
**Use a command-oriented CLI as a thin adapter over a standalone library, with CLI-owned config discovery, mandatory help/version/verbose flags, and consistent progress and exit behavior.**
|
|
18
|
+
|
|
19
|
+
This keeps the user-facing command predictable while preserving a clean library API for embedding, testing, and automation.
|
|
20
|
+
|
|
21
|
+
### Implementation Details
|
|
22
|
+
|
|
23
|
+
#### CLI command surface
|
|
24
|
+
|
|
25
|
+
- CLI tools should default to the format `[tool] [command] [options] [arguments]`.
|
|
26
|
+
- Example: `filedist extract --packages=test mydir`
|
|
27
|
+
- A single-action tool may omit `[command]` only when adding a subcommand would be artificial and there is no meaningful action split.
|
|
28
|
+
- Every CLI tool must expose:
|
|
29
|
+
- `--help` on the root command
|
|
30
|
+
- `--version` on the root command
|
|
31
|
+
- `--verbose` on the root command and on subcommands when flags are parsed per command
|
|
32
|
+
- Root `--help` output must list all available commands, key options, and usage examples. Command-specific help must describe that command's arguments and options.
|
|
33
|
+
|
|
34
|
+
#### CLI to library separation
|
|
35
|
+
|
|
36
|
+
- Structure the software as `cli -> lib`.
|
|
37
|
+
- The CLI layer must only parse arguments, load config, call the library, and format output.
|
|
38
|
+
- Domain logic must live in the library and be usable without CLI globals such as `argv`, `stdout`, or process exit handlers.
|
|
39
|
+
- Every feature available through the CLI must also be available through the library API.
|
|
40
|
+
- Organize the library by action so the mapping stays direct and obvious.
|
|
41
|
+
- `extract` command -> `extract(...)`
|
|
42
|
+
- `validate` command -> `validate(...)`
|
|
43
|
+
- Avoid one generic library `run()` entry point that hides action-specific contracts behind switches or string commands.
|
|
44
|
+
|
|
45
|
+
#### Library API shape
|
|
46
|
+
|
|
47
|
+
- Each CLI action should map to a dedicated exported API with typed inputs and outputs appropriate for the language.
|
|
48
|
+
- Library APIs should accept in-memory options objects or typed parameters, not require config files or environment variables unless library-level config-file support is an explicit requirement.
|
|
49
|
+
- The CLI layer is responsible for translating flags, positional arguments, and config-file contents into library inputs.
|
|
50
|
+
- The library should return explicit results and errors so the CLI can decide what to print and which exit code to use.
|
|
51
|
+
|
|
52
|
+
#### Configuration
|
|
53
|
+
|
|
54
|
+
- Prefer flags and positional arguments for simple inputs.
|
|
55
|
+
- When configuration becomes long, nested, or repetitive, support a config file instead of pushing all values into flags.
|
|
56
|
+
- By default, config-file discovery and loading must happen in the CLI layer, not in the library layer.
|
|
57
|
+
- When a config file is supported, the CLI should try to load a JSON config file from `[cwd]/.[cli-name]rc` by default.
|
|
58
|
+
- The CLI should also support an explicit config path flag such as `--config`.
|
|
59
|
+
- For JavaScript tools, `cosmiconfig` is an acceptable implementation. Equivalent discovery libraries are acceptable in other ecosystems.
|
|
60
|
+
- The library must not depend on the presence of the config file; it should receive parsed configuration values from the CLI layer.
|
|
61
|
+
- The library may load or parse config files only when that behavior is an explicit requirement of the library contract for non-CLI consumers as well.
|
|
62
|
+
|
|
63
|
+
#### Output and progress
|
|
64
|
+
|
|
65
|
+
- Standard output must show a start message when work begins and a result message when work completes successfully.
|
|
66
|
+
- When processing is long-running or multi-stage, print concise intermediate progress messages.
|
|
67
|
+
- `--verbose` must reveal more internal detail about what the tool is doing without changing the meaning of the command result.
|
|
68
|
+
- Default output should stay concise and readable for humans.
|
|
69
|
+
- Errors should be written to standard error with an actionable message. Stack traces or raw internal errors should stay hidden by default and may be shown in verbose mode.
|
|
70
|
+
|
|
71
|
+
#### Exit behavior
|
|
72
|
+
|
|
73
|
+
- Exit with `0` only when the requested action completed successfully.
|
|
74
|
+
- Exit with `1` when the requested action could not be completed.
|
|
75
|
+
- The library should surface failure as return values, result objects, or language-idiomatic errors; the CLI is responsible for converting that outcome into user-facing messages and process exit codes.
|
|
76
|
+
|
|
77
|
+
#### Documentation
|
|
78
|
+
|
|
79
|
+
- `README.md` must include at least 4 CLI usage examples.
|
|
80
|
+
- `README.md` must include at least 2 library API examples for the same operation also available through the CLI.
|
|
81
|
+
- If the tool supports config files, at least 1 README example should show config-file usage.
|
|
82
|
+
- Examples must use the public command and public library API, not internal modules or private files.
|
|
83
|
+
|
|
84
|
+
#### Distribution and versioning
|
|
85
|
+
|
|
86
|
+
- The implementation language is project-dependent, but the packaging and entry-point strategy must match how users are expected to run the tool.
|
|
87
|
+
- Choose language tooling that stays compatible with ecosystem launchers such as `npx`, `pnpm dlx`, `uvx`, or equivalent distribution commands for that ecosystem.
|
|
88
|
+
- `--version` must print the same version declared in the published package or release artifact metadata.
|
|
89
|
+
- Do not hard-code a second version string that can drift from the published package version.
|
|
90
|
+
- Language-specific project structure and packaging rules still apply and should be combined with this XDR, especially [agentme-edr-003](003-javascript-project-tooling.md), [agentme-edr-010](010-golang-project-tooling.md), and [agentme-edr-014](014-python-project-tooling.md).
|
|
91
|
+
|
|
92
|
+
## Considered Options
|
|
93
|
+
|
|
94
|
+
* (REJECTED) **Ad hoc CLIs with embedded business logic** - Keep parsing, processing, config loading, and output formatting inside a single entry point.
|
|
95
|
+
* Reason: Makes the tool hard to test, hard to reuse as a library, and inconsistent across commands.
|
|
96
|
+
* (CHOSEN) **Thin CLI adapter over action-oriented library APIs** - Keep the CLI responsible for user interaction and the library responsible for the actual behavior.
|
|
97
|
+
* Reason: Preserves a clean programmatic API, keeps command behavior discoverable, and makes the CLI-to-library mapping easy to maintain.
|
|
98
|
+
|
|
99
|
+
## References
|
|
100
|
+
|
|
101
|
+
- [agentme-edr-003](003-javascript-project-tooling.md) - JavaScript project packaging and structure
|
|
102
|
+
- [agentme-edr-007](../principles/007-project-quality-standards.md) - README and examples baseline
|
|
103
|
+
- [agentme-edr-008](../devops/008-common-targets.md) - Standard command names for project entry points
|
|
104
|
+
- [agentme-edr-009](../principles/009-error-handling.md) - Process error signaling and error handling expectations
|
|
105
|
+
- [agentme-edr-010](010-golang-project-tooling.md) - Go CLI structure and verbose logging baseline
|
|
106
|
+
- [agentme-edr-014](014-python-project-tooling.md) - Python packaging and CLI entry-point guidance
|
|
107
|
+
- [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig) - Example JSON configuration discovery library for JavaScript CLIs
|
|
@@ -13,12 +13,13 @@ compatibility: JavaScript/TypeScript, Node.js 18+
|
|
|
13
13
|
|
|
14
14
|
## Overview
|
|
15
15
|
|
|
16
|
-
Creates a complete JavaScript/TypeScript library project from scratch. The layout
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
Creates a complete JavaScript/TypeScript library project from scratch. The layout keeps the
|
|
17
|
+
published package self-contained in its module root (`lib/`), places runnable consumer examples in
|
|
18
|
+
the sibling `examples/` folder, redirects persistent caches into `.cache/`, and uses Makefiles as
|
|
19
|
+
the only entry points. Boilerplate is derived from the [filedist](https://github.com/flaviostutz/filedist)
|
|
19
20
|
project.
|
|
20
21
|
|
|
21
|
-
Related
|
|
22
|
+
Related EDRs: [agentme-edr-003](../../003-javascript-project-tooling.md), [agentme-edr-016](../../../principles/016-cross-language-module-structure.md)
|
|
22
23
|
|
|
23
24
|
## Instructions
|
|
24
25
|
|
|
@@ -72,6 +73,7 @@ pnpm = "10.14.0"
|
|
|
72
73
|
```
|
|
73
74
|
node_modules/
|
|
74
75
|
dist/
|
|
76
|
+
.cache/
|
|
75
77
|
*.tgz
|
|
76
78
|
.filedist
|
|
77
79
|
```
|
|
@@ -105,24 +107,29 @@ describe('hello', () => {
|
|
|
105
107
|
```makefile
|
|
106
108
|
SHELL := /bin/bash
|
|
107
109
|
MISE := mise exec --
|
|
110
|
+
CACHE_DIR := .cache
|
|
108
111
|
|
|
109
112
|
build: install
|
|
110
113
|
@rm -rf dist
|
|
111
|
-
$(
|
|
114
|
+
@mkdir -p $(CACHE_DIR)/tsc
|
|
115
|
+
$(MISE) pnpm exec tsc --incremental --tsBuildInfoFile $(CACHE_DIR)/tsc/tsconfig.tsbuildinfo --outDir dist
|
|
112
116
|
@-find ./dist \( -regex '.*\.test\..*' -o -regex '.*__tests.*' \) -exec rm -rf {} \; 2> /dev/null
|
|
113
117
|
@# Create pack for use by examples to simulate real external usage
|
|
114
118
|
$(MISE) pnpm pack --pack-destination dist
|
|
115
119
|
|
|
116
120
|
build-module: install
|
|
117
121
|
@rm -rf dist
|
|
118
|
-
$(
|
|
122
|
+
@mkdir -p $(CACHE_DIR)/tsc
|
|
123
|
+
$(MISE) pnpm exec tsc --incremental --tsBuildInfoFile $(CACHE_DIR)/tsc/tsconfig.tsbuildinfo --outDir dist
|
|
119
124
|
@-find ./dist \( -regex '.*\.test\..*' -o -regex '.*__tests.*' \) -exec rm -rf {} \; 2> /dev/null
|
|
120
125
|
|
|
121
126
|
lint:
|
|
122
|
-
$(
|
|
127
|
+
@mkdir -p $(CACHE_DIR)/eslint
|
|
128
|
+
$(MISE) pnpm exec eslint ./src --cache --cache-location $(CACHE_DIR)/eslint/.eslintcache
|
|
123
129
|
|
|
124
130
|
lint-fix:
|
|
125
|
-
$(
|
|
131
|
+
@mkdir -p $(CACHE_DIR)/eslint
|
|
132
|
+
$(MISE) pnpm exec eslint ./src --fix --cache --cache-location $(CACHE_DIR)/eslint/.eslintcache
|
|
126
133
|
|
|
127
134
|
test-watch:
|
|
128
135
|
$(MISE) pnpm exec jest --watch
|
|
@@ -133,6 +140,7 @@ test:
|
|
|
133
140
|
clean:
|
|
134
141
|
rm -rf node_modules
|
|
135
142
|
rm -rf dist
|
|
143
|
+
rm -rf .cache
|
|
136
144
|
|
|
137
145
|
all: build lint test
|
|
138
146
|
|
|
@@ -223,6 +231,8 @@ Use this single tsconfig for both build and type-aware linting. Keep `*.test.ts`
|
|
|
223
231
|
module.exports = {
|
|
224
232
|
testEnvironment: 'node',
|
|
225
233
|
testMatch: ['**/*.test.ts'],
|
|
234
|
+
cacheDirectory: '<rootDir>/.cache/jest',
|
|
235
|
+
coverageDirectory: '<rootDir>/.cache/coverage',
|
|
226
236
|
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.test.ts'],
|
|
227
237
|
transform: {
|
|
228
238
|
'^.+\\.tsx?$': [
|
|
@@ -323,7 +333,29 @@ console.log(result);
|
|
|
323
333
|
|
|
324
334
|
---
|
|
325
335
|
|
|
326
|
-
### Phase 5: Create `README.md`
|
|
336
|
+
### Phase 5: Create `README.md` and `lib/README.md`
|
|
337
|
+
|
|
338
|
+
Keep the repository README focused on the workspace and the module README focused on consumers of
|
|
339
|
+
the published package.
|
|
340
|
+
|
|
341
|
+
**`README.md`**
|
|
342
|
+
|
|
343
|
+
```markdown
|
|
344
|
+
# [package-name]
|
|
345
|
+
|
|
346
|
+
[description]
|
|
347
|
+
|
|
348
|
+
## Getting Started
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
mise install
|
|
352
|
+
make test
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The published module lives in `lib/` and runnable consumer examples live in `examples/`.
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**`lib/README.md`**
|
|
327
359
|
|
|
328
360
|
Quick Start must appear at the top — it is rendered first on the npm registry page.
|
|
329
361
|
|
|
@@ -334,28 +366,37 @@ Quick Start must appear at the top — it is rendered first on the npm registry
|
|
|
334
366
|
|
|
335
367
|
## Quick Start
|
|
336
368
|
|
|
337
|
-
|
|
369
|
+
```bash
|
|
338
370
|
pnpm add [package-name]
|
|
339
|
-
|
|
371
|
+
```
|
|
340
372
|
|
|
341
|
-
|
|
373
|
+
```typescript
|
|
342
374
|
import { hello } from '[package-name]';
|
|
343
375
|
|
|
344
376
|
const greeting = hello('world');
|
|
345
377
|
console.log(greeting); // Hello, world!
|
|
346
|
-
|
|
378
|
+
```
|
|
347
379
|
|
|
348
380
|
## Installation
|
|
349
381
|
|
|
350
|
-
|
|
382
|
+
```bash
|
|
351
383
|
npm install [package-name]
|
|
352
384
|
# or
|
|
353
385
|
pnpm add [package-name]
|
|
354
|
-
|
|
386
|
+
```
|
|
355
387
|
|
|
356
388
|
## Examples
|
|
357
389
|
|
|
358
|
-
See the
|
|
390
|
+
See the sibling `examples/` folder for complete runnable examples that consume the packed artifact
|
|
391
|
+
from `lib/dist/`.
|
|
392
|
+
|
|
393
|
+
## Development
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
make build
|
|
397
|
+
make lint
|
|
398
|
+
make test
|
|
399
|
+
```
|
|
359
400
|
|
|
360
401
|
## License
|
|
361
402
|
|
|
@@ -369,12 +410,13 @@ MIT
|
|
|
369
410
|
Review all created files and confirm:
|
|
370
411
|
|
|
371
412
|
- [ ] Root `Makefile` delegates to both `lib/` and `examples/`
|
|
413
|
+
- [ ] `.gitignore` ignores `dist/` and `.cache/`
|
|
372
414
|
- [ ] `lib/src/index.ts` exports at least one symbol
|
|
373
415
|
- [ ] `lib/src/index.test.ts` has at least one passing test
|
|
374
416
|
- [ ] `lib/package.json` has `main`, `types`, and `files` set correctly
|
|
375
417
|
- [ ] `lib/tsconfig.json` includes co-located `src/**/*.test.ts` files for ESLint type-aware parsing
|
|
376
418
|
- [ ] `lib/eslint.config.mjs` points `parserOptions.project` to `tsconfig.json`
|
|
377
|
-
- [ ] `README.md` starts with Quick Start
|
|
419
|
+
- [ ] `lib/README.md` starts with Quick Start and ends with module development commands
|
|
378
420
|
- [ ] All `[package-name]` placeholders are replaced with the actual name
|
|
379
421
|
- [ ] Structure matches the layout in [agentme-edr-003](../../003-javascript-project-tooling.md)
|
|
380
422
|
|
|
@@ -384,9 +426,9 @@ Review all created files and confirm:
|
|
|
384
426
|
|
|
385
427
|
**Agent action:** Gathers: name=`retry-client`, default Node.js 24, then creates:
|
|
386
428
|
- `./Makefile`, `./.mise.toml`, `./.gitignore`
|
|
387
|
-
- `lib/src/index.ts`, `lib/src/index.test.ts`, `lib/Makefile`, `lib/package.json`, `lib/tsconfig.json`, `lib/jest.config.js`, `lib/eslint.config.mjs`
|
|
429
|
+
- `lib/src/index.ts`, `lib/src/index.test.ts`, `lib/Makefile`, `lib/README.md`, `lib/package.json`, `lib/tsconfig.json`, `lib/jest.config.js`, `lib/eslint.config.mjs`
|
|
388
430
|
- `examples/Makefile`, `examples/usage-basic/package.json`, `examples/usage-basic/index.js`
|
|
389
|
-
- `README.md` (
|
|
431
|
+
- `README.md` (workspace overview)
|
|
390
432
|
|
|
391
433
|
All `[package-name]` replaced with `retry-client`.
|
|
392
434
|
|