Use when working within any module under `modules.root_paths` from `.agent-project-settings.yml` — Laravel HMVC, Symfony DDD-lite, Node monorepo, Python src/, Go internal/, or a custom path.
Scanned 6/5/2026
Install via CLI
openskills install event4u-app/agent-config---
model_tier: medium
name: module-management
description: "Use when working within any module under `modules.root_paths` from `.agent-project-settings.yml` — Laravel HMVC, Symfony DDD-lite, Node monorepo, Python src/, Go internal/, or a custom path."
domain: process
workspaces:
- agent-config-maintainer
packs:
- meta
---
# module
## When to use
Use this skill when creating, exploring, or working within a module under
any directory listed in `modules.root_paths` (team setting in
`.agent-project-settings.yml`). The skill is stack-agnostic — Laravel
HMVC, Symfony DDD-lite, Node monorepo, Python src layout, Go internal/,
or a custom path all flow through the same procedure with a
stack-specific carve-out at the bottom.
When `modules.enabled` is `false` (the default) the skill is a no-op —
the project does not opt into module-aware behavior.
## Understand the current layout before editing
Before creating, renaming, or modifying anything inside a module:
1. Read the `modules:` block from `.agent-project-settings.yml` —
never assume a specific module root.
2. List the existing modules under each `modules.root_paths` entry and
review the target module's `README.md` (or `package.json` /
`pyproject.toml` description) to understand its purpose.
3. Read any module-scoped agent docs under
`{module_root}/{ModuleName}/{modules.agent_folder}/contexts/`.
4. Match the stack carve-out below by `modules.namespace_template`
shape and confirm the conventions before generating files.
Skip this step → risk creating files in the wrong root, breaking
stack-native auto-loading, or duplicating existing modules.
## Procedure: Work with modules
1. Read `modules:` block from `.agent-project-settings.yml` via the
loader (`get_modules_config()` in `scripts/_lib/agent_settings.py`).
2. For each path in `modules.root_paths`, read the module's `README.md`
(or `package.json` / `pyproject.toml` description) for purpose.
3. If module-level agent docs exist under
`{module_root}/{modules.agent_folder}/` (default `agents/`), read them.
4. Match the stack carve-out below by `modules.namespace_template` shape
or root-path heuristic — apply stack-specific conventions on top of
the generic procedure.
## Detection (fallback when `modules:` block is empty)
When `modules.enabled` is unset / false, the skill consults the
auto-detection table in
[`/module explore` Step 1](../../commands/module/explore.md) — same six
stack shapes, fallback only. The skill never writes the `modules:`
block automatically; that is `propose_modules_config.py` plus user
confirmation per
[`/agents init`](../../commands/agents/init.md) Step 7.
## Generic module structure
```
{module_root}/{ModuleName}/
├── <stack-native source layout> # see carve-out below
├── tests/ # module-specific tests
├── README.md # module description
└── {modules.agent_folder}/ # default: agents/
├── features/ # module-scoped feature plans
├── roadmaps/ # module-scoped roadmaps
└── contexts/ # module-scoped context docs
```
The agent-folder name comes from `modules.agent_folder` (default
`agents`). Skip directories listed in `modules.skip_dirs` (default
`.module-template`, `.example`).
## Stack carve-outs
Apply the section that matches the project's
`modules.namespace_template` and root-path layout.
### Laravel HMVC carve-out
**Triggers when:** `modules.namespace_template` starts with
`App\Modules\` or root path is `app/Modules`.
```
app/Modules/{ModuleName}/
├── App/ # PSR-4 source (capitalized)
│ ├── Console/Commands/ # auto-registered
│ ├── Http/{Controllers,Middleware,Requests}/
│ ├── Jobs/ Models/ Services/ Rules/ Enums/
├── Routes/ # auto-loaded
│ ├── api.php web.php console.php
├── Tests/{Unit,Integration,Component}/
└── agents/
```
**Namespace:** `App\Modules\{ModuleName}\App\{Layer}\{Class}` — note the
extra `App` segment.
**Auto-loading:** `app/Providers/ModuleServiceProvider.php` scans
`app/Modules/` and registers routes (`Routes/api.php` → `/api` prefix +
`api` middleware; `Routes/web.php` → `web` middleware) plus Artisan
commands under `App/Console/Commands/`.
**Route conventions:**
```php
// Routes/api.php — auto-prefixed /api
Route::name('v1.')->prefix('v1/{module-prefix}')->group(function(): void {
Route::get('/', [Controller::class, 'index'])->name('{module-prefix}.index');
});
```
Module name = PascalCase. Route prefix = kebab-case. Route names = dot
notation.
### Symfony DDD-lite carve-out
**Triggers when:** `modules.namespace_template` starts with `App\` (no
`Modules` segment) or root path is `src/` with `<Domain>/` subdirs.
```
src/{Domain}/
├── Application/ # use cases, command handlers
├── Domain/ # entities, value objects
├── Infrastructure/ # adapters, repositories
├── UserInterface/ # controllers, console
└── Tests/
```
**Namespace:** `App\{Domain}\{Layer}\{Class}` — no extra segment.
**Auto-loading:** Symfony service container auto-wires each
`{Domain}/` subtree per `services.yaml` resource imports.
### Node monorepo carve-out
**Triggers when:** root path is `packages/` and each child has
`package.json`.
```
packages/{pkg-name}/
├── package.json
├── src/ # entry points re-exported via "main"
├── tests/ __tests__/
└── README.md
```
**Module identity** comes from `package.json#name`, not the directory
name. The agent folder still lives at
`packages/{pkg-name}/{modules.agent_folder}/`.
### Python src-layout carve-out
**Triggers when:** root path is `src/` and each child has `__init__.py`.
```
src/{package_name}/
├── __init__.py
├── <module files>
└── tests/ # or root-level tests/{package_name}/
```
**Namespace** is the import path: `{package_name}.<sub>.<class>`. Project
metadata in `pyproject.toml`.
### Go internal carve-out
**Triggers when:** root path is `internal/` (one-level structure).
```
internal/{pkgname}/
├── *.go # package files
└── *_test.go # tests colocated
```
**Import path:** `{module-path-from-go.mod}/internal/{pkgname}`. No
top-level grouping — each subdir of `internal/` is its own package.
## Output format
1. Module directory under the matched stack carve-out.
2. Stack-native auto-loading + routing (if applicable).
3. Optional per-module `{modules.agent_folder}/` scaffold.
## Auto-trigger keywords
- module structure
- module creation
- module namespace
- create / explore module
- per-module agent docs
### Validate
- Verify namespace matches `modules.namespace_template` (when set).
- Run stack-native auto-loading check (e.g. `php artisan route:list` for
Laravel HMVC, `bin/console debug:container` for Symfony,
`npm test --workspace=<pkg>` for Node monorepo).
- Run module tests — must pass.
- Run quality tools scoped to the new path.
## Gotcha
- **Laravel HMVC only** — namespace has the extra `App` segment
(`App\Modules\X\App\…`). Other stacks do **not**.
- Routes auto-register in Laravel HMVC and Symfony — don't register
manually.
- Shared code lives outside module roots — never inside
`modules.root_paths`.
- Capitalize directory names only where the stack requires it (Laravel
PSR-4 yes, Node `packages/` no).
## Do NOT
- Do NOT hardcode any stack-specific module root (Laravel
`<app>/<Modules>/`, Symfony `src/Domain`, Node `packages/`, …) in
skill bodies, commands, or context docs — read from
`modules.root_paths`.
- Do NOT create a module for trivial functionality — only when logical
separation is needed.
- Do NOT register module routes manually when the stack provides
auto-loading.
- Do NOT add the `framework: laravel` frontmatter back to this skill —
the lint guard fails the build.
No comments yet. Be the first to comment!