agentme 0.10.0 → 0.12.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/.filedist-package.yml +1 -1
- package/.xdrs/agentme/edrs/application/003-javascript-project-tooling.md +41 -5
- package/.xdrs/agentme/edrs/application/010-golang-project-tooling.md +39 -15
- package/.xdrs/agentme/edrs/application/014-python-project-tooling.md +76 -17
- package/.xdrs/agentme/edrs/application/015-cli-tool-standards.md +25 -24
- package/.xdrs/agentme/edrs/application/018-ai-agent-development-standards.md +29 -11
- package/.xdrs/agentme/edrs/application/021-pragmatic-hexagonal-architecture.md +112 -0
- package/.xdrs/agentme/edrs/application/skills/001-create-javascript-project/SKILL.md +26 -11
- package/.xdrs/agentme/edrs/application/skills/003-create-golang-project/SKILL.md +31 -14
- package/.xdrs/agentme/edrs/application/skills/005-create-python-project/SKILL.md +64 -33
- package/.xdrs/agentme/edrs/devops/005-monorepo-structure.md +1 -1
- package/.xdrs/agentme/edrs/devops/006-github-pipelines.md +1 -1
- package/.xdrs/agentme/edrs/devops/008-common-targets.md +1 -1
- package/.xdrs/agentme/edrs/devops/017-tool-execution-and-scripting.md +2 -2
- package/.xdrs/agentme/edrs/governance/013-contributing-guide-requirements.md +1 -1
- package/.xdrs/agentme/edrs/index.md +2 -0
- package/.xdrs/agentme/edrs/observability/011-service-health-check-endpoint.md +1 -1
- package/.xdrs/agentme/edrs/principles/002-coding-best-practices.md +1 -1
- package/.xdrs/agentme/edrs/principles/004-unit-test-requirements.md +8 -2
- package/.xdrs/agentme/edrs/principles/007-project-quality-standards.md +3 -3
- package/.xdrs/agentme/edrs/principles/009-error-handling.md +1 -1
- package/.xdrs/agentme/edrs/principles/012-continuous-xdr-enrichment.md +2 -2
- package/.xdrs/agentme/edrs/principles/016-cross-language-module-structure.md +1 -1
- package/.xdrs/agentme/edrs/principles/022-secrets-management.md +128 -0
- package/.xdrs/agentme/edrs/principles/articles/001-continuous-xdr-improvement.md +5 -5
- package/package.json +2 -2
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentme-edr-policy-021-pragmatic-hexagonal-architecture
|
|
3
|
+
description: Defines a pragmatic variant of Hexagonal Architecture for organizing application source code into Adapters (inbound/outbound I/O boundaries) and Application (business logic) layers, with explicit naming conventions and folder structure. Use when designing or reviewing the internal layout of application modules.
|
|
4
|
+
apply-to: All application projects
|
|
5
|
+
valid-from: 2026-05-28
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# agentme-edr-policy-021: Pragmatic hexagonal architecture
|
|
9
|
+
|
|
10
|
+
## Context and Problem Statement
|
|
11
|
+
|
|
12
|
+
Applications often mix business logic with infrastructure concerns (database access, HTTP handling, environment variable reading), making code hard to test, refactor, and reuse.
|
|
13
|
+
|
|
14
|
+
How should application source code be organized to separate business logic from infrastructure while avoiding unnecessary abstraction layers?
|
|
15
|
+
|
|
16
|
+
## Decision Outcome
|
|
17
|
+
|
|
18
|
+
**Organize application source code into three conceptual layers — External (not in codebase), Adapters (inbound/outbound I/O boundaries), and Application (business logic exposed as typed library interfaces) — following a pragmatic variant of Hexagonal Architecture that avoids unnecessary abstractions.**
|
|
19
|
+
|
|
20
|
+
### Details
|
|
21
|
+
|
|
22
|
+
#### 01-three-layer-separation
|
|
23
|
+
|
|
24
|
+
Every application is conceptually divided into three layers:
|
|
25
|
+
|
|
26
|
+
| Layer | Description |
|
|
27
|
+
|-------|-------------|
|
|
28
|
+
| **External** | Systems outside the codebase boundary (databases, third-party APIs, message brokers, filesystems, users) |
|
|
29
|
+
| **Adapters** | Bridge between External and Application — translate external protocols into application calls and vice versa |
|
|
30
|
+
| **Application** | Business logic that delegates I/O to adapters |
|
|
31
|
+
|
|
32
|
+
#### 02-adapter-naming-conventions
|
|
33
|
+
|
|
34
|
+
**Inbound adapters** receive external requests or events and trigger application logic. Each gets a flat folder under `adapters/`:
|
|
35
|
+
|
|
36
|
+
- `cli/` — command-line interface entry point
|
|
37
|
+
- `http/` — HTTP/REST server
|
|
38
|
+
- `grpc/` — gRPC server
|
|
39
|
+
- `ws/` — WebSocket server
|
|
40
|
+
- `kafka/` — Kafka consumer
|
|
41
|
+
- `mqtt/` — MQTT subscriber
|
|
42
|
+
- Additional inbound adapters are allowed with descriptive names
|
|
43
|
+
|
|
44
|
+
**Outbound adapters** are called by the application to reach external systems. They live under `adapters/connectors/` with one subfolder per external resource, named descriptively:
|
|
45
|
+
|
|
46
|
+
- e.g.: `stripe-api/`, `config-file/`, `s3-datalake/`, `whatsapp/`, `postgres/`, `redis-cache/`
|
|
47
|
+
|
|
48
|
+
**Clarification:** "inbound" means the adapter triggers application logic in response to an external stimulus. "Outbound" means the application calls the adapter to interact with an external system.
|
|
49
|
+
|
|
50
|
+
#### 03-application-layer-rules
|
|
51
|
+
|
|
52
|
+
- Expose functionality as typed library interfaces
|
|
53
|
+
- All inputs must be explicitly passed as typed parameters
|
|
54
|
+
- No global variables, no direct environment variable access in `app/` or `shared/`
|
|
55
|
+
- Business logic with well-defined input/output behavior
|
|
56
|
+
- Group related logic into subfolders (aggregation roots)
|
|
57
|
+
- Environment variables must be read only in the bootstrap/entry-point layer of inbound adapters, converted into typed configuration objects, and passed explicitly to all other components
|
|
58
|
+
|
|
59
|
+
#### 04-mandatory-folder-structure
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
mysystem/
|
|
63
|
+
Makefile # targets to run different inbound interfaces (e.g. run-http, run-cli)
|
|
64
|
+
src/
|
|
65
|
+
adapters/ # mandatory
|
|
66
|
+
cli/ # if CLI exists — bootstrap/entry point for CLI
|
|
67
|
+
http/ # if HTTP server exists — bootstrap/entry point for HTTP
|
|
68
|
+
grpc/ # if gRPC exists
|
|
69
|
+
connectors/ # if external resource access exists
|
|
70
|
+
postgres/ # one folder per external resource
|
|
71
|
+
stripe-api/
|
|
72
|
+
app/ # mandatory — core business logic
|
|
73
|
+
feature1.ts
|
|
74
|
+
feature-group/ # optional subfolders for grouping
|
|
75
|
+
shared/ # utilities and functions shared among adapters and app
|
|
76
|
+
logging.ts
|
|
77
|
+
errors.ts
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`shared/` must contain only infrastructure-agnostic utilities — not business rules or domain logic.
|
|
81
|
+
|
|
82
|
+
#### 05-pragmatic-coupling
|
|
83
|
+
|
|
84
|
+
- Application MAY import from Adapters when it simplifies the design
|
|
85
|
+
- Avoid excessive abstractions, interface types, and indirection layers
|
|
86
|
+
- Only introduce interfaces or abstract types when building a framework where the extra complexity demonstrably pays off
|
|
87
|
+
- Prefer concrete implementations over abstract ports — skip the purism of classic Hexagonal Architecture in favor of practicality
|
|
88
|
+
- Some coupling between Application and Adapters is acceptable and expected
|
|
89
|
+
|
|
90
|
+
#### 06-bootstrap-and-entry-points
|
|
91
|
+
|
|
92
|
+
- Each inbound adapter folder (`cli/`, `http/`, `grpc/`, etc.) contains the bootstrap and entry point for that interface
|
|
93
|
+
- The project root Makefile must have targets to run the different inbound interfaces following [agentme-edr-008](../devops/008-common-targets.md) extension conventions (e.g. `run-http`, `run-grpc`)
|
|
94
|
+
- Bootstrap code lives in the adapter that receives inbound requests, not in a separate wiring layer
|
|
95
|
+
|
|
96
|
+
#### 07-minimum-complexity-threshold
|
|
97
|
+
|
|
98
|
+
- Trivial scripts and single-purpose tools (fewer than ~300 lines with a single I/O boundary) MAY skip this layering
|
|
99
|
+
- All other projects MUST use this structure from the start
|
|
100
|
+
|
|
101
|
+
#### 08-examples-of-data-flow
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
HTTP request → adapters/http/ → app/create-user → adapters/connectors/postgres/
|
|
105
|
+
CLI command → adapters/cli/ → app/create-dir → adapters/connectors/local-fs/
|
|
106
|
+
Kafka message → adapters/kafka/ → app/process-event → adapters/connectors/stripe-api/
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## References
|
|
110
|
+
|
|
111
|
+
- [agentme-edr-016](../principles/016-cross-language-module-structure.md) — Defines the module-root structure (Makefile, dist/, .cache/) that wraps this internal layout
|
|
112
|
+
- [agentme-edr-002](../principles/002-coding-best-practices.md) — File size limits and code organization practices that complement this architecture
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agentme-edr-skill-001-create-javascript-project
|
|
3
3
|
description: >
|
|
4
|
-
Scaffolds the initial boilerplate structure for a JavaScript/TypeScript
|
|
4
|
+
Scaffolds the initial boilerplate structure for a JavaScript/TypeScript project following
|
|
5
5
|
the standard tooling and layout defined in agentme-edr-003. Activate this skill when the user
|
|
6
|
-
asks to create, scaffold, or initialize a new JavaScript or TypeScript
|
|
6
|
+
asks to create, scaffold, or initialize a new JavaScript or TypeScript project, npm
|
|
7
7
|
package, or similar project structure.
|
|
8
8
|
metadata:
|
|
9
9
|
author: flaviostutz
|
|
@@ -13,13 +13,14 @@ compatibility: JavaScript/TypeScript, Node.js 18+
|
|
|
13
13
|
|
|
14
14
|
## Overview
|
|
15
15
|
|
|
16
|
-
Creates a complete JavaScript/TypeScript
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
Creates a complete JavaScript/TypeScript project from scratch. The layout keeps the
|
|
17
|
+
package self-contained in its module root (`lib/`), organizes internal code following
|
|
18
|
+
[agentme-edr-021](../../021-pragmatic-hexagonal-architecture.md) (`adapters/`, `app/`, `shared/`),
|
|
19
|
+
places runnable consumer examples in the sibling `examples/` folder, redirects persistent caches
|
|
20
|
+
into `.cache/`, and uses Makefiles as the only entry points. Boilerplate is derived from the
|
|
21
|
+
[filedist](https://github.com/flaviostutz/filedist) project.
|
|
21
22
|
|
|
22
|
-
Related EDRs: [agentme-edr-003](../../003-javascript-project-tooling.md), [agentme-edr-016](../../../principles/016-cross-language-module-structure.md)
|
|
23
|
+
Related EDRs: [agentme-edr-003](../../003-javascript-project-tooling.md), [agentme-edr-016](../../../principles/016-cross-language-module-structure.md), [agentme-edr-021](../../021-pragmatic-hexagonal-architecture.md)
|
|
23
24
|
|
|
24
25
|
## Instructions
|
|
25
26
|
|
|
@@ -82,7 +83,7 @@ dist/
|
|
|
82
83
|
|
|
83
84
|
### Phase 3: Create `lib/`
|
|
84
85
|
|
|
85
|
-
**`lib/src/
|
|
86
|
+
**`lib/src/app/hello.ts`** — business logic:
|
|
86
87
|
|
|
87
88
|
```typescript
|
|
88
89
|
export const hello = (name: string): string => {
|
|
@@ -90,10 +91,10 @@ export const hello = (name: string): string => {
|
|
|
90
91
|
};
|
|
91
92
|
```
|
|
92
93
|
|
|
93
|
-
**`lib/src/
|
|
94
|
+
**`lib/src/app/hello.test.ts`** — co-located unit test:
|
|
94
95
|
|
|
95
96
|
```typescript
|
|
96
|
-
import { hello } from './
|
|
97
|
+
import { hello } from './hello';
|
|
97
98
|
|
|
98
99
|
describe('hello', () => {
|
|
99
100
|
it('should return a greeting', () => {
|
|
@@ -102,6 +103,20 @@ describe('hello', () => {
|
|
|
102
103
|
});
|
|
103
104
|
```
|
|
104
105
|
|
|
106
|
+
**`lib/src/index.ts`** — public API re-export from `app/`:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
export { hello } from './app/hello';
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**`lib/src/adapters/`** — create empty directories for the hexagonal structure:
|
|
113
|
+
|
|
114
|
+
- `lib/src/adapters/` — inbound adapters (add `cli/`, `http/`, etc. as needed)
|
|
115
|
+
- `lib/src/adapters/connectors/` — outbound adapters (one folder per external resource)
|
|
116
|
+
- `lib/src/shared/` — infrastructure-agnostic utilities
|
|
117
|
+
|
|
118
|
+
Create a placeholder `.gitkeep` in `lib/src/adapters/` and `lib/src/shared/` so the directories are tracked.
|
|
119
|
+
|
|
105
120
|
**`lib/Makefile`**:
|
|
106
121
|
|
|
107
122
|
```makefile
|
|
@@ -12,9 +12,9 @@ compatibility: Go 1.21+
|
|
|
12
12
|
|
|
13
13
|
## Overview
|
|
14
14
|
|
|
15
|
-
Creates a complete Go
|
|
15
|
+
Creates a complete Go project from scratch, following the layout from [agentme-edr-010](../../010-golang-project-tooling.md) and [agentme-edr-021](../../021-pragmatic-hexagonal-architecture.md). Business logic lives in `app/<feature>/` packages; CLI wiring lives in `adapters/cli/`; outbound integrations live in `adapters/connectors/`; `main.go` is a thin dispatcher. The module root owns its `Makefile`, `README.md`, `dist/`, and `.cache/` folders.
|
|
16
16
|
|
|
17
|
-
Related EDRs: [agentme-edr-010](../../010-golang-project-tooling.md), [agentme-edr-016](../../../principles/016-cross-language-module-structure.md)
|
|
17
|
+
Related EDRs: [agentme-edr-010](../../010-golang-project-tooling.md), [agentme-edr-016](../../../principles/016-cross-language-module-structure.md), [agentme-edr-021](../../021-pragmatic-hexagonal-architecture.md)
|
|
18
18
|
|
|
19
19
|
## Instructions
|
|
20
20
|
|
|
@@ -67,7 +67,7 @@ import (
|
|
|
67
67
|
"fmt"
|
|
68
68
|
"os"
|
|
69
69
|
|
|
70
|
-
cli
|
|
70
|
+
cli "[module]/adapters/cli"
|
|
71
71
|
)
|
|
72
72
|
|
|
73
73
|
func main() {
|
|
@@ -78,7 +78,7 @@ func main() {
|
|
|
78
78
|
|
|
79
79
|
switch os.Args[1] {
|
|
80
80
|
case "[subcommand]":
|
|
81
|
-
cli[Feature]
|
|
81
|
+
cli.Run[Feature](os.Args)
|
|
82
82
|
default:
|
|
83
83
|
fmt.Printf("Unknown command: %s\n", os.Args[1])
|
|
84
84
|
fmt.Println("Usage: [binary] [[feature]]")
|
|
@@ -216,7 +216,7 @@ coverage.out
|
|
|
216
216
|
|
|
217
217
|
### Phase 3: Create the feature package
|
|
218
218
|
|
|
219
|
-
**`[feature]/[feature].go`** (replace `[feature]`, `[Feature]`):
|
|
219
|
+
**`app/[feature]/[feature].go`** (replace `[feature]`, `[Feature]`):
|
|
220
220
|
|
|
221
221
|
```go
|
|
222
222
|
package [feature]
|
|
@@ -246,7 +246,7 @@ func Run(opts Options) (Result, error) {
|
|
|
246
246
|
}
|
|
247
247
|
```
|
|
248
248
|
|
|
249
|
-
**`[feature]/[feature]_test.go`** (replace `[feature]`, `[Feature]`):
|
|
249
|
+
**`app/[feature]/[feature]_test.go`** (replace `[feature]`, `[Feature]`):
|
|
250
250
|
|
|
251
251
|
```go
|
|
252
252
|
package [feature]
|
|
@@ -267,12 +267,12 @@ func Test[Feature]Run(t *testing.T) {
|
|
|
267
267
|
|
|
268
268
|
---
|
|
269
269
|
|
|
270
|
-
### Phase 4: Create the CLI
|
|
270
|
+
### Phase 4: Create the CLI adapter
|
|
271
271
|
|
|
272
|
-
**`cli/[feature]
|
|
272
|
+
**`adapters/cli/[feature].go`** (replace `[module]`, `[feature]`, `[Feature]`, `[subcommand]`):
|
|
273
273
|
|
|
274
274
|
```go
|
|
275
|
-
package cli
|
|
275
|
+
package cli
|
|
276
276
|
|
|
277
277
|
import (
|
|
278
278
|
"flag"
|
|
@@ -280,11 +280,11 @@ import (
|
|
|
280
280
|
"os"
|
|
281
281
|
|
|
282
282
|
"github.com/sirupsen/logrus"
|
|
283
|
-
"[module]/[feature]"
|
|
283
|
+
"[module]/app/[feature]"
|
|
284
284
|
)
|
|
285
285
|
|
|
286
|
-
// Run parses CLI flags for the [subcommand] command and calls the domain package.
|
|
287
|
-
func Run(args []string) {
|
|
286
|
+
// Run[Feature] parses CLI flags for the [subcommand] command and calls the domain package.
|
|
287
|
+
func Run[Feature](args []string) {
|
|
288
288
|
fs := flag.NewFlagSet("[subcommand]", flag.ExitOnError)
|
|
289
289
|
verbose := fs.Bool("verbose", false, "Show verbose logs during processing")
|
|
290
290
|
|
|
@@ -309,6 +309,21 @@ func Run(args []string) {
|
|
|
309
309
|
}
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
+
**`shared/logging.go`** (optional, scaffold if needed):
|
|
313
|
+
|
|
314
|
+
```go
|
|
315
|
+
package shared
|
|
316
|
+
|
|
317
|
+
import "github.com/sirupsen/logrus"
|
|
318
|
+
|
|
319
|
+
// SetupLogging configures the global log level.
|
|
320
|
+
func SetupLogging(verbose bool) {
|
|
321
|
+
if verbose {
|
|
322
|
+
logrus.SetLevel(logrus.DebugLevel)
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
312
327
|
---
|
|
313
328
|
|
|
314
329
|
### Phase 5: Verify and run
|
|
@@ -327,8 +342,10 @@ Fix any compile or lint errors before finishing.
|
|
|
327
342
|
## Conventions and reminders
|
|
328
343
|
|
|
329
344
|
- `main.go` dispatches only — no logic.
|
|
330
|
-
- Business logic only in `
|
|
331
|
-
- `cli
|
|
345
|
+
- Business logic only in `app/<feature>/` packages — no flag parsing, no `fmt.Println` for diagnostics.
|
|
346
|
+
- `adapters/cli/` owns flag parsing, output formatting, and the wiring between flags and `app/` functions. No business logic lives in adapter packages.
|
|
347
|
+
- Outbound adapters live under `adapters/connectors/` with one subfolder per external resource (e.g., `postgres/`, `stripe-api/`, `redis-cache/`).
|
|
348
|
+
- `shared/` must contain only infrastructure-agnostic utilities — not business rules or domain logic.
|
|
332
349
|
- All tests co-located (`*_test.go` next to the file under test).
|
|
333
350
|
- Use `tests_integration/` for integration flows and `tests_benchmark/` when benchmarks need dedicated harnesses or datasets.
|
|
334
351
|
- Log with `logrus`; never use `fmt.Println` for diagnostic/debug output.
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agentme-edr-skill-005-create-python-project
|
|
3
3
|
description: >
|
|
4
|
-
Scaffolds the initial boilerplate structure for a Python
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
structure.
|
|
4
|
+
Scaffolds the initial boilerplate structure for a Python project following the standard tooling
|
|
5
|
+
and layout defined in agentme-edr-014. Activate this skill when the user asks to create,
|
|
6
|
+
scaffold, or initialize a new Python package, CLI, or similar project structure.
|
|
8
7
|
metadata:
|
|
9
8
|
author: flaviostutz
|
|
10
9
|
version: "1.0"
|
|
@@ -14,11 +13,12 @@ compatibility: Python 3.12+
|
|
|
14
13
|
## Overview
|
|
15
14
|
|
|
16
15
|
Creates a complete Python project from scratch using Mise, `uv`, `pyproject.toml`, Ruff,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
ty, Pytest, and Makefiles. The layout keeps the package self-contained under `lib/`,
|
|
17
|
+
organizes internal code following [agentme-edr-021](../../021-pragmatic-hexagonal-architecture.md)
|
|
18
|
+
(`adapters/`, `app/`, `shared/`), uses a shared root `.venv/`, redirects persistent caches into
|
|
19
|
+
`.cache/`, and places runnable consumer projects under the sibling `examples/` folder.
|
|
20
20
|
|
|
21
|
-
Related EDRs: [agentme-edr-014](../../014-python-project-tooling.md), [agentme-edr-016](../../../principles/016-cross-language-module-structure.md)
|
|
21
|
+
Related EDRs: [agentme-edr-014](../../014-python-project-tooling.md), [agentme-edr-016](../../../principles/016-cross-language-module-structure.md), [agentme-edr-021](../../021-pragmatic-hexagonal-architecture.md)
|
|
22
22
|
|
|
23
23
|
## Instructions
|
|
24
24
|
|
|
@@ -30,7 +30,6 @@ Ask for or infer from context:
|
|
|
30
30
|
- **Short description** - one sentence
|
|
31
31
|
- **Author** name or GitHub username
|
|
32
32
|
- **Python version** - default `3.13`
|
|
33
|
-
- **Project kind** - `library` or `cli`
|
|
34
33
|
- **Primary entry point** - first module or command name to scaffold
|
|
35
34
|
- **GitHub repo URL** - optional, for project metadata
|
|
36
35
|
- **Confirm target directory** - default: current workspace root
|
|
@@ -105,6 +104,7 @@ The root `Makefile` keeps the repository clean by delegating package work to `li
|
|
|
105
104
|
.venv/
|
|
106
105
|
dist/
|
|
107
106
|
.cache/
|
|
107
|
+
__pycache__/
|
|
108
108
|
```
|
|
109
109
|
|
|
110
110
|
**`./README.md`**
|
|
@@ -157,13 +157,13 @@ build: install
|
|
|
157
157
|
lint: install
|
|
158
158
|
$(MISE) uv run --project . ruff format --check .
|
|
159
159
|
$(MISE) uv run --project . ruff check .
|
|
160
|
-
$(MISE) uv run --project .
|
|
160
|
+
$(MISE) uv run --project . ty check
|
|
161
161
|
$(MISE) uv run --project . pip-audit
|
|
162
162
|
|
|
163
163
|
lint-fix: install
|
|
164
164
|
$(MISE) uv run --project . ruff format .
|
|
165
165
|
$(MISE) uv run --project . ruff check . --fix
|
|
166
|
-
$(MISE) uv run --project .
|
|
166
|
+
$(MISE) uv run --project . ty check
|
|
167
167
|
$(MISE) uv run --project . pip-audit
|
|
168
168
|
|
|
169
169
|
test-unit: install
|
|
@@ -203,7 +203,7 @@ dev = []
|
|
|
203
203
|
[dependency-groups]
|
|
204
204
|
dev = [
|
|
205
205
|
"pip-audit>=2.9.0",
|
|
206
|
-
"
|
|
206
|
+
"ty>=0.1.0",
|
|
207
207
|
"pytest>=8.4.0",
|
|
208
208
|
"pytest-cov>=6.1.0",
|
|
209
209
|
"ruff>=0.11.0",
|
|
@@ -214,25 +214,40 @@ requires = ["hatchling>=1.27.0"]
|
|
|
214
214
|
build-backend = "hatchling.build"
|
|
215
215
|
|
|
216
216
|
[tool.ruff]
|
|
217
|
-
|
|
217
|
+
cache-dir = ".cache/ruff"
|
|
218
|
+
output-format = "grouped"
|
|
219
|
+
line-length = 120
|
|
218
220
|
target-version = "py313"
|
|
221
|
+
src = ["src", "tests", "tests_integration"]
|
|
222
|
+
|
|
223
|
+
[tool.ruff.format]
|
|
224
|
+
docstring-code-format = true
|
|
225
|
+
line-ending = "lf"
|
|
219
226
|
|
|
220
227
|
[tool.ruff.lint]
|
|
221
|
-
|
|
228
|
+
task-tags = ["TODO"]
|
|
229
|
+
select = ["ERA", "FAST", "ANN", "ASYNC", "S", "BLE", "FBT", "B", "A", "COM",
|
|
230
|
+
"C4", "DTZ", "T10", "DJ", "EM", "EXE", "FIX", "INT", "ISC", "ICN", "LOG", "G",
|
|
231
|
+
"INP", "PIE", "T20", "PYI", "PT", "Q", "RSE", "RET", "SLF", "SIM", "SLOT", "TID",
|
|
232
|
+
"TC", "ARG", "PTH", "FLY", "I", "C90", "NPY", "PD", "N", "PERF", "E", "W",
|
|
233
|
+
"D", "F", "PGH", "PL", "UP", "FURB", "RUF", "TRY"]
|
|
234
|
+
ignore = ["ANN002", "ANN003", "ANN401", "D100", "D101", "D102", "D103", "D104",
|
|
235
|
+
"D105", "D106", "D107", "COM812", "D203", "D213", "D400", "D401", "D404", "D415", "FIX002"]
|
|
236
|
+
|
|
237
|
+
[tool.ruff.lint.pycodestyle]
|
|
238
|
+
ignore-overlong-task-comments = true
|
|
222
239
|
|
|
223
|
-
[tool.
|
|
224
|
-
|
|
225
|
-
venvPath = ".."
|
|
226
|
-
venv = ".venv"
|
|
227
|
-
typeCheckingMode = "standard"
|
|
240
|
+
[tool.ty]
|
|
241
|
+
src = ["src", "tests"]
|
|
228
242
|
|
|
229
243
|
[tool.pytest.ini_options]
|
|
230
244
|
testpaths = ["tests"]
|
|
245
|
+
python_files = "*_test.py"
|
|
231
246
|
addopts = "-q"
|
|
232
247
|
```
|
|
233
248
|
|
|
234
249
|
Use `lib/pyproject.toml` as the single configuration file for the package. Do not add
|
|
235
|
-
`requirements.txt`, `setup.py`, `setup.cfg`, `ruff.toml`, or `
|
|
250
|
+
`requirements.txt`, `setup.py`, `setup.cfg`, `ruff.toml`, or `ty.toml` by default.
|
|
236
251
|
|
|
237
252
|
**`lib/README.md`**
|
|
238
253
|
|
|
@@ -267,29 +282,37 @@ make test
|
|
|
267
282
|
|
|
268
283
|
### Phase 4: Create the package and tests inside `lib/`
|
|
269
284
|
|
|
270
|
-
Create this baseline structure.
|
|
285
|
+
Create this baseline structure following [agentme-edr-021](../../021-pragmatic-hexagonal-architecture.md).
|
|
271
286
|
|
|
272
287
|
**`lib/src/[package_name]/__init__.py`**
|
|
273
288
|
|
|
274
289
|
```python
|
|
275
|
-
from .
|
|
290
|
+
from .app.hello import hello
|
|
276
291
|
|
|
277
292
|
__all__ = ["hello"]
|
|
278
293
|
```
|
|
279
294
|
|
|
280
|
-
**`lib/src/[package_name]/
|
|
295
|
+
**`lib/src/[package_name]/app/__init__.py`**
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**`lib/src/[package_name]/app/hello.py`**
|
|
281
301
|
|
|
282
302
|
```python
|
|
283
303
|
def hello(name: str) -> str:
|
|
284
304
|
return f"Hello, {name}!"
|
|
285
305
|
```
|
|
286
306
|
|
|
287
|
-
**`lib/src/[package_name]/
|
|
307
|
+
**`lib/src/[package_name]/adapters/__init__.py`**
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
```
|
|
288
311
|
|
|
289
|
-
|
|
312
|
+
**`lib/src/[package_name]/adapters/cli/__init__.py`**
|
|
290
313
|
|
|
291
314
|
```python
|
|
292
|
-
from .
|
|
315
|
+
from [package_name].app.hello import hello
|
|
293
316
|
|
|
294
317
|
|
|
295
318
|
def main() -> None:
|
|
@@ -300,10 +323,17 @@ if __name__ == "__main__":
|
|
|
300
323
|
main()
|
|
301
324
|
```
|
|
302
325
|
|
|
303
|
-
**`lib/
|
|
326
|
+
**`lib/src/[package_name]/shared/__init__.py`**
|
|
327
|
+
|
|
328
|
+
```python
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Create empty `adapters/connectors/` directory with a `.gitkeep` for outbound adapters.
|
|
332
|
+
|
|
333
|
+
**`lib/tests/hello_test.py`**
|
|
304
334
|
|
|
305
335
|
```python
|
|
306
|
-
from [package_name].
|
|
336
|
+
from [package_name].app.hello import hello
|
|
307
337
|
|
|
308
338
|
|
|
309
339
|
def test_hello() -> None:
|
|
@@ -314,9 +344,9 @@ If two or more test files need shared fixtures, create `lib/tests/conftest.py` a
|
|
|
314
344
|
|
|
315
345
|
If the module needs slower end-to-end coverage, place those tests in `lib/tests_integration/`. Put dedicated benchmark harnesses in `lib/tests_benchmark/`.
|
|
316
346
|
|
|
317
|
-
### Phase 5: Create examples
|
|
347
|
+
### Phase 5: Create examples
|
|
318
348
|
|
|
319
|
-
|
|
349
|
+
Add an `examples/` directory with one subdirectory per runnable consumer example. Each example must be its own Python project.
|
|
320
350
|
|
|
321
351
|
**`examples/basic-usage/pyproject.toml`**
|
|
322
352
|
|
|
@@ -355,14 +385,15 @@ After creating the files:
|
|
|
355
385
|
|
|
356
386
|
## Examples
|
|
357
387
|
|
|
358
|
-
**Input:** "Create a Python
|
|
388
|
+
**Input:** "Create a Python project called `event_tools`"
|
|
359
389
|
- Create `Makefile`, `README.md`, `lib/pyproject.toml`, `lib/Makefile`, `lib/src/event_tools/`, `lib/tests/`, and `examples/`
|
|
390
|
+
- Scaffold `adapters/`, `app/`, `shared/` directories inside `lib/src/event_tools/`
|
|
360
391
|
- Add `lib/README.md`, `.cache/` handling, and install examples from the built wheel in `lib/dist/`
|
|
361
|
-
- Configure `uv`, Ruff,
|
|
392
|
+
- Configure `uv`, Ruff, ty, Pytest, `pytest-cov`, and `pip-audit`
|
|
362
393
|
- Verify with `make lint-fix`, `make test`, and `make build`
|
|
363
394
|
|
|
364
395
|
**Input:** "Scaffold a Python CLI package"
|
|
365
|
-
- Add `lib/src/<package_name>/
|
|
396
|
+
- Add CLI entry point in `lib/src/<package_name>/adapters/cli/__init__.py`
|
|
366
397
|
- Add `[project.scripts]` in `lib/pyproject.toml` when the command name must differ from the module name
|
|
367
398
|
- Keep the same Makefile and quality checks
|
|
368
399
|
|
|
@@ -20,7 +20,7 @@ What monorepo structure, naming conventions, tooling, and build standards should
|
|
|
20
20
|
For step-by-step scaffolding instructions see [skill 002-monorepo-setup](skills/002-monorepo-setup/SKILL.md).
|
|
21
21
|
Module folder responsibilities, artifact locations, and test-folder conventions follow [agentme-edr-016](../principles/016-cross-language-module-structure.md).
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### Details
|
|
24
24
|
|
|
25
25
|
#### 01-top-level-directory-layout
|
|
26
26
|
|
|
@@ -19,7 +19,7 @@ What GitHub Actions workflows should every project follow to ensure a safe, pred
|
|
|
19
19
|
|
|
20
20
|
Separating these concerns eliminates accidental publishes from CI runs, ensures monotag has access to the full git history, and makes each workflow independently auditable and re-runnable.
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Details
|
|
23
23
|
|
|
24
24
|
#### Workflow overview
|
|
25
25
|
|
|
@@ -19,7 +19,7 @@ What standard set of Makefile target names and execution rules should projects a
|
|
|
19
19
|
|
|
20
20
|
Standardizing both the target names and the execution chain removes per-project guesswork, makes CI pipelines reusable, and keeps tooling behavior visible in one place.
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Details
|
|
23
23
|
|
|
24
24
|
#### 01-every-project-must-have-root-makefile
|
|
25
25
|
|
|
@@ -19,7 +19,7 @@ How should projects execute development commands so the command surface stays pr
|
|
|
19
19
|
|
|
20
20
|
This keeps local development and CI aligned, reduces indirection, and lets contributors understand project behavior by reading one command surface.
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Details
|
|
23
23
|
|
|
24
24
|
- Every project MUST use a root `Makefile` as the authoritative entry point for developer and pipeline commands.
|
|
25
25
|
- The target names in that `Makefile` MUST follow [agentme-edr-008](008-common-targets.md).
|
|
@@ -27,7 +27,7 @@ This keeps local development and CI aligned, reduces indirection, and lets contr
|
|
|
27
27
|
- A Makefile target MUST execute the real operation through `mise exec --` before invoking the tool itself, so it always uses the version pinned in `.mise.toml`. Avoid intermediate script layers that hide the actual command.
|
|
28
28
|
- Every Makefile target MUST start by echoing a concise summary of the target and folder or context, using fewer than 10 words. When delegating to another Makefile, echo the child path and delegated target before invoking it.
|
|
29
29
|
- Direct delegation to another Makefile is allowed when traversing repo, app, or module boundaries, for example `$(MAKE) -C lib build`.
|
|
30
|
-
- Calling the actual tool binary through its native executable launcher is allowed when that is the direct command under `mise exec --`, for example `mise exec -- pnpm exec eslint ./src`, `mise exec -- uv run
|
|
30
|
+
- Calling the actual tool binary through its native executable launcher is allowed when that is the direct command under `mise exec --`, for example `mise exec -- pnpm exec eslint ./src`, `mise exec -- uv run ty check`, `mise exec -- go test`, or `mise exec -- npx -y monotag`.
|
|
31
31
|
- Makefile targets MUST use `mise exec --` consistently before routine tool commands and MUST NOT call `npm run`, `pnpm run`, `yarn run`, `just`, `task`, or similar abstraction layers for routine project commands.
|
|
32
32
|
- Tool installation and environment preparation MUST be handled explicitly in developer setup instructions and CI workflow steps, using ecosystem-specific installation steps such as `actions/setup-node`, `actions/setup-go`, `astral-sh/setup-uv`, system package managers, or pinned install commands such as `mise install`.
|
|
33
33
|
- `package.json` scripts are optional and MAY exist only as direct reverse-compatibility aliases to one Make target, for example `"test": "make test"`. They MUST stay one-to-one and add no extra orchestration.
|
|
@@ -19,7 +19,7 @@ What contributor workflow guidance must every project publish so contributors kn
|
|
|
19
19
|
|
|
20
20
|
Projects must keep a `CONTRIBUTING.md` file at the repository root. The file must explain where bugs, feature discussions, and code changes belong so contributors follow a predictable workflow before opening pull requests.
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Details
|
|
23
23
|
|
|
24
24
|
- Every project **MUST** have a root `CONTRIBUTING.md`.
|
|
25
25
|
- The guide **MUST** direct bug reports to issues.
|
|
@@ -14,6 +14,7 @@ Foundational standards, principles, and guidelines.
|
|
|
14
14
|
- [agentme-edr-009](principles/009-error-handling.md) - **Error handling** - Standardize explicit errors, logging, and propagation rules
|
|
15
15
|
- [agentme-edr-012](principles/012-continuous-xdr-enrichment.md) - **Continuous xdr improvement policy** - Promote recurring delivery lessons into reusable XDRs
|
|
16
16
|
- [agentme-edr-016](principles/016-cross-language-module-structure.md) - **Cross-language module structure** - Organize modules consistently across supported languages
|
|
17
|
+
- [agentme-edr-022](principles/022-secrets-management.md) - **Secrets management** - Handle secrets securely using native keychains and cloud secret managers
|
|
17
18
|
|
|
18
19
|
## Articles
|
|
19
20
|
|
|
@@ -32,6 +33,7 @@ Language and framework-specific tooling and project structure.
|
|
|
32
33
|
- [agentme-edr-018](application/018-ai-agent-development-standards.md) - **AI agent development standards** - Standard toolchain, framework, evaluation, and workflow patterns for AI agent projects built with Python and LangGraph
|
|
33
34
|
- [agentme-edr-019](application/019-ml-dataset-structure.md) - **ML dataset structure** - Standard folder layout and file conventions for ML datasets
|
|
34
35
|
- [agentme-edr-020](application/020-ai-agent-xdrs-knowledge-layer.md) - **AI agent XDRS knowledge layer** - How to integrate XDRS as the runtime source of truth for policies and skills in AI agents (apply only when the project explicitly uses XDRS)
|
|
36
|
+
- [agentme-edr-021](application/021-pragmatic-hexagonal-architecture.md) - **Pragmatic hexagonal architecture** - Organize application layers as External/Adapters/Application with practical coupling rules
|
|
35
37
|
- [004-select-relevant-xdrs](application/skills/004-select-relevant-xdrs/SKILL.md) - **Select relevant XDRs**
|
|
36
38
|
|
|
37
39
|
## Devops
|
|
@@ -19,7 +19,7 @@ How should services expose their health status and validate operational readines
|
|
|
19
19
|
|
|
20
20
|
All services must expose a `GET /health` endpoint that validates external dependencies using read-only operations and returns structured status with appropriate HTTP codes.
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Details
|
|
23
23
|
|
|
24
24
|
**Endpoint contract:**
|
|
25
25
|
|
|
@@ -17,7 +17,7 @@ What coding practices should be followed across all languages and projects to ke
|
|
|
17
17
|
|
|
18
18
|
**Apply a set of language-agnostic structural and organizational practices that keep files small, logic decomposed, types co-located, tests co-located, and documentation always in sync.**
|
|
19
19
|
|
|
20
|
-
###
|
|
20
|
+
### Details
|
|
21
21
|
|
|
22
22
|
#### 01-keep-files-short
|
|
23
23
|
|
|
@@ -17,7 +17,7 @@ What unit testing practices should be followed to ensure tests are meaningful, r
|
|
|
17
17
|
|
|
18
18
|
**Every test must assert behavior, run offline without external dependencies, enforce 80% coverage, centralize shared setup, and prefer real code over mocks.**
|
|
19
19
|
|
|
20
|
-
###
|
|
20
|
+
### Details
|
|
21
21
|
|
|
22
22
|
#### 01-must-have-at-least-one-assertion-per-test
|
|
23
23
|
|
|
@@ -70,7 +70,13 @@ Builds that miss the threshold must not be merged.
|
|
|
70
70
|
|
|
71
71
|
#### 04-must-place-test-files-alongside-source
|
|
72
72
|
|
|
73
|
-
Test files must live next to the source file they test, in the same directory, following the convention of the language/framework
|
|
73
|
+
Test files must live next to the source file they test, in the same directory, following the convention of the language/framework:
|
|
74
|
+
|
|
75
|
+
| Language | Pattern | Example |
|
|
76
|
+
|----------|---------|-------|
|
|
77
|
+
| TypeScript/JavaScript | `[name].test.ts` or `[name].spec.js` | `file1.test.ts` |
|
|
78
|
+
| Go | `[name]_test.go` | `file1_test.go` |
|
|
79
|
+
| Python | `[name]_test.py` | `myfunc_test.py` |
|
|
74
80
|
|
|
75
81
|
```
|
|
76
82
|
src/mymodule/group1/file1.ts ← source
|