agent-orchestrator-kit 0.1.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/LICENSE +21 -0
- package/README.md +446 -0
- package/bin/agent-orchestrator.js +229 -0
- package/package.json +48 -0
- package/profiles/generic/orchestrator.yaml +54 -0
- package/profiles/node/orchestrator.yaml +57 -0
- package/profiles/vue3/README.md +19 -0
- package/profiles/vue3/orchestrator.yaml +59 -0
- package/templates/.agents/commands/opsx-apply.md +155 -0
- package/templates/.agents/commands/opsx-archive.md +160 -0
- package/templates/.agents/commands/opsx-explore.md +172 -0
- package/templates/.agents/commands/opsx-propose.md +107 -0
- package/templates/.agents/commands/opsx-review.md +125 -0
- package/templates/.agents/commands/opsx-sync.md +143 -0
- package/templates/.agents/mcp.json.example +11 -0
- package/templates/.agents/rules/agent-orchestration.mdc +29 -0
- package/templates/.agents/rules/memory-mcp-autosetup.mdc +55 -0
- package/templates/.agents/rules/openspec-workflow.mdc +39 -0
- package/templates/.agents/skills/agent-orchestration/SKILL.md +146 -0
- package/templates/AGENTS.md +81 -0
- package/templates/CLAUDE.md +49 -0
- package/templates/orchestrator.yaml +57 -0
- package/templates/scripts/sync-local-agent-skills.sh +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maksim Shevyakov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# agent-orchestrator-kit
|
|
2
|
+
|
|
3
|
+
Universal AI agent orchestration kit for **Cursor**, **Claude Code**, and **Amp Code** — spec-driven pipeline built on [OpenSpec](https://github.com/fission-ai/openspec).
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/agent-orchestrator-kit)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
## What It Is
|
|
9
|
+
|
|
10
|
+
A portable kit that installs a **5-role AI pipeline** into any project:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
explore → propose → review → apply → verify → archive
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Each role runs in a **separate agent session** with dedicated permissions, model hints, and handoff gates. The `openspec/changes/` folder acts as the **contract between agents** — no shared memory between sessions, only files.
|
|
17
|
+
|
|
18
|
+
Works with:
|
|
19
|
+
- [Cursor](https://cursor.sh) — via `.cursor/rules/` + `.cursor/skills/`
|
|
20
|
+
- [Claude Code](https://code.claude.com) — via `CLAUDE.md` + `.claude/skills/`
|
|
21
|
+
- [Amp Code](https://ampcode.com) — via `AGENTS.md` + `.agents/skills/` (native, no sync needed)
|
|
22
|
+
|
|
23
|
+
## Why
|
|
24
|
+
|
|
25
|
+
Without role separation, AI agents tend to mix thinking with implementation, skip spec review, and accumulate context debt across one long chat. This kit enforces the discipline at the filesystem level: each role has explicit allowed files, a checklist, and a handoff gate before the next role starts.
|
|
26
|
+
|
|
27
|
+
The `AGENTS.md` / `CLAUDE.md` files tell each IDE exactly what the roles are, so you don't repeat yourself every session.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
### Prerequisites
|
|
32
|
+
|
|
33
|
+
- Node.js ≥ 18
|
|
34
|
+
- [OpenSpec](https://github.com/fission-ai/openspec) installed in the project:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm i -D @fission-ai/openspec
|
|
38
|
+
npx openspec init
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Install the kit
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx agent-orchestrator-kit init
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
With a stack profile:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx agent-orchestrator-kit init --profile vue3
|
|
51
|
+
npx agent-orchestrator-kit init --profile node
|
|
52
|
+
npx agent-orchestrator-kit init --profile generic
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
With options:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx agent-orchestrator-kit init \
|
|
59
|
+
--profile vue3 \
|
|
60
|
+
--name "My Project" \
|
|
61
|
+
--lang uk
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Sync to local IDEs
|
|
65
|
+
|
|
66
|
+
After init (and after every update):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
./scripts/sync-local-agent-skills.sh
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This copies `.agents/` to your local IDE directories (not committed to git).
|
|
73
|
+
|
|
74
|
+
## What Gets Installed
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
your-project/
|
|
78
|
+
├── AGENTS.md # Amp Code + universal pipeline manifest
|
|
79
|
+
├── CLAUDE.md # Claude Code context
|
|
80
|
+
├── .agents/
|
|
81
|
+
│ ├── orchestrator.yaml # Pipeline config (committed)
|
|
82
|
+
│ ├── mcp.json.example # MCP template
|
|
83
|
+
│ ├── commands/
|
|
84
|
+
│ │ ├── opsx-explore.md
|
|
85
|
+
│ │ ├── opsx-propose.md
|
|
86
|
+
│ │ ├── opsx-review.md # new: read-only spec review
|
|
87
|
+
│ │ ├── opsx-apply.md
|
|
88
|
+
│ │ ├── opsx-archive.md
|
|
89
|
+
│ │ └── opsx-sync.md
|
|
90
|
+
│ ├── rules/
|
|
91
|
+
│ │ ├── agent-orchestration.mdc
|
|
92
|
+
│ │ ├── openspec-workflow.mdc
|
|
93
|
+
│ │ └── memory-mcp-autosetup.mdc
|
|
94
|
+
│ └── skills/
|
|
95
|
+
│ └── agent-orchestration/
|
|
96
|
+
│ └── SKILL.md
|
|
97
|
+
└── scripts/
|
|
98
|
+
└── sync-local-agent-skills.sh
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Git-committed: `.agents/` + `AGENTS.md` + `CLAUDE.md` + `scripts/`
|
|
102
|
+
Local only (not committed): `.cursor/` `.claude/` `.amp/`
|
|
103
|
+
|
|
104
|
+
## IDE Integration
|
|
105
|
+
|
|
106
|
+
### Amp Code (primary — zero config)
|
|
107
|
+
|
|
108
|
+
Amp reads `.agents/skills/` and `AGENTS.md` **natively** — no sync needed.
|
|
109
|
+
|
|
110
|
+
1. Install the kit → `AGENTS.md` is created automatically.
|
|
111
|
+
2. Amp picks up skills from `.agents/skills/` on session start.
|
|
112
|
+
3. Configure Memory MCP in `.amp/settings.json`:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"amp.mcpServers": {
|
|
117
|
+
"memory": {
|
|
118
|
+
"command": "npx",
|
|
119
|
+
"args": ["-y", "@modelcontextprotocol/server-memory"],
|
|
120
|
+
"env": { "MEMORY_FILE_PATH": ".cursor/memory.json" }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
4. Use commands directly:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
/opsx:explore
|
|
130
|
+
/opsx:propose add-feature-name
|
|
131
|
+
/opsx:review add-feature-name
|
|
132
|
+
/opsx:apply add-feature-name
|
|
133
|
+
/opsx:archive
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Model hints per role** (Amp modes):
|
|
137
|
+
|
|
138
|
+
| Role | Recommended Amp mode |
|
|
139
|
+
|------|---------------------|
|
|
140
|
+
| explore | `rush` |
|
|
141
|
+
| propose | `smart` or `deep` |
|
|
142
|
+
| review | `smart` |
|
|
143
|
+
| apply (complex) | `smart` or `deep` |
|
|
144
|
+
| apply (simple task) | `rush` |
|
|
145
|
+
|
|
146
|
+
Switch modes in Amp CLI: `Ctrl+O` → `mode`.
|
|
147
|
+
|
|
148
|
+
### Claude Code
|
|
149
|
+
|
|
150
|
+
1. Run sync: `./scripts/sync-local-agent-skills.sh`
|
|
151
|
+
2. This creates:
|
|
152
|
+
- `.claude/CLAUDE.md` — project context
|
|
153
|
+
- `.claude/skills/` — all skills from `.agents/skills/`
|
|
154
|
+
3. Skills are auto-loaded by Claude Code from `.claude/skills/`.
|
|
155
|
+
4. Invoke directly: `/agent-orchestration`, `/openspec-howto`, etc.
|
|
156
|
+
|
|
157
|
+
**CLAUDE.md tiers used:**
|
|
158
|
+
- Project level: `.claude/CLAUDE.md` (synced from `CLAUDE.md`)
|
|
159
|
+
- Personal (optional): `~/.claude/CLAUDE.md` for preferences
|
|
160
|
+
|
|
161
|
+
**Claude Code subagent config** (in skill frontmatter):
|
|
162
|
+
|
|
163
|
+
```yaml
|
|
164
|
+
---
|
|
165
|
+
name: openspec-explore
|
|
166
|
+
context: fork
|
|
167
|
+
agent: Explore
|
|
168
|
+
allowed-tools: Read, Bash
|
|
169
|
+
---
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The kit pre-configures Explore skills to use `context: fork` + `agent: Explore` for clean context isolation.
|
|
173
|
+
|
|
174
|
+
### Cursor
|
|
175
|
+
|
|
176
|
+
1. Run sync: `./scripts/sync-local-agent-skills.sh`
|
|
177
|
+
2. Creates:
|
|
178
|
+
- `.cursor/skills/` — all skills
|
|
179
|
+
- `.cursor/rules/` — `.mdc` rule files
|
|
180
|
+
- `.mcp.json` — from `mcp.json.example` (if not present)
|
|
181
|
+
3. Rules are applied automatically per `alwaysApply: true`.
|
|
182
|
+
|
|
183
|
+
**Memory MCP for Cursor** (`.mcp.json`):
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"mcpServers": {
|
|
188
|
+
"memory": {
|
|
189
|
+
"command": "npx",
|
|
190
|
+
"args": ["-y", "@modelcontextprotocol/server-memory"],
|
|
191
|
+
"env": { "MEMORY_FILE_PATH": ".cursor/memory.json" }
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## The Pipeline in Detail
|
|
198
|
+
|
|
199
|
+
### Role 1: Explorer — `/opsx:explore`
|
|
200
|
+
|
|
201
|
+
**Mode:** read-only. Cannot edit any files.
|
|
202
|
+
**Model:** fast/cheap.
|
|
203
|
+
**Purpose:** Understand the problem. Surface options. Choose a direction.
|
|
204
|
+
|
|
205
|
+
**Exit criteria (before starting Architect):**
|
|
206
|
+
- Problem stated in 3–5 sentences
|
|
207
|
+
- 2–3 solution options + recommendation
|
|
208
|
+
- kebab-case change name chosen
|
|
209
|
+
- Non-goals listed
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
/opsx:explore How should we handle bulk camera export?
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### Role 2: Architect — `/opsx:propose <name>`
|
|
218
|
+
|
|
219
|
+
**Mode:** writes `openspec/changes/<name>/` only. Cannot touch `src/`.
|
|
220
|
+
**Model:** strong reasoning.
|
|
221
|
+
**Purpose:** Create all change artifacts: proposal, design, tasks, delta specs.
|
|
222
|
+
|
|
223
|
+
**Exit gate:**
|
|
224
|
+
```bash
|
|
225
|
+
openspec validate <name> --strict --type change # must be ✓
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
/opsx:propose add-bulk-camera-export
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
### Role 3: Spec Reviewer — `/opsx:review <name>`
|
|
235
|
+
|
|
236
|
+
**Mode:** read-only. No code edits.
|
|
237
|
+
**Model:** medium or strong.
|
|
238
|
+
**Purpose:** Review artifacts. Output **Approve ✓** or **Request Changes ✗**.
|
|
239
|
+
|
|
240
|
+
Checks:
|
|
241
|
+
- Acceptance criteria are testable
|
|
242
|
+
- Tasks ≤ ~2 hours each
|
|
243
|
+
- No scope creep vs Non-goals
|
|
244
|
+
- No conflicts with existing domain specs
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
/opsx:review add-bulk-camera-export
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Only after explicit APPROVE can apply start.**
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### Role 4: Implementer — `/opsx:apply <name>`
|
|
255
|
+
|
|
256
|
+
**Mode:** writes `src/`. Marks `tasks.md [x]`.
|
|
257
|
+
**Model:** strong. Use fast for simple mechanical tasks.
|
|
258
|
+
**Purpose:** Implement tasks. One session = 1–3 tasks (not all 15 at once).
|
|
259
|
+
|
|
260
|
+
**Exit gate:**
|
|
261
|
+
```bash
|
|
262
|
+
npm run build # must pass
|
|
263
|
+
npm run lint # must pass
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
/opsx:apply add-bulk-camera-export
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
### Role 5: Verifier — CI (automatic)
|
|
273
|
+
|
|
274
|
+
```yaml
|
|
275
|
+
# .github/workflows/agent-verify.yml (generated by kit)
|
|
276
|
+
- run: npx openspec validate --all --strict
|
|
277
|
+
- run: npm run lint
|
|
278
|
+
- run: npm run build
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Blocks merge if any gate fails.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
### Archive — `/opsx:archive`
|
|
286
|
+
|
|
287
|
+
After PR merged + CI green:
|
|
288
|
+
```
|
|
289
|
+
/opsx:archive add-bulk-camera-export
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Merges delta specs into `openspec/specs/` and moves change to `archive/`.
|
|
293
|
+
|
|
294
|
+
## Configuration
|
|
295
|
+
|
|
296
|
+
Edit `.agents/orchestrator.yaml` after init:
|
|
297
|
+
|
|
298
|
+
```yaml
|
|
299
|
+
project:
|
|
300
|
+
name: "My Project"
|
|
301
|
+
agent_language: uk # response language for agents
|
|
302
|
+
|
|
303
|
+
pipeline:
|
|
304
|
+
require_spec_review: true
|
|
305
|
+
max_active_changes: 1
|
|
306
|
+
archive_after_merge: true
|
|
307
|
+
|
|
308
|
+
verifier:
|
|
309
|
+
lint_command: "npm run lint"
|
|
310
|
+
build_command: "npm run build"
|
|
311
|
+
test_command: "npm test" # optional
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Update
|
|
315
|
+
|
|
316
|
+
When a new version of the kit is released:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
npx agent-orchestrator-kit update
|
|
320
|
+
./scripts/sync-local-agent-skills.sh
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
`update` only touches kit-managed files (commands, rules, skills). It never overwrites:
|
|
324
|
+
- `orchestrator.yaml`
|
|
325
|
+
- `openspec/config.yaml`
|
|
326
|
+
- `openspec/specs/`
|
|
327
|
+
- `openspec/changes/`
|
|
328
|
+
- Any project-conventions skills
|
|
329
|
+
|
|
330
|
+
## Profiles
|
|
331
|
+
|
|
332
|
+
| Profile | Stack | Extra skills installed |
|
|
333
|
+
|---------|-------|----------------------|
|
|
334
|
+
| `generic` | Any | Orchestration only |
|
|
335
|
+
| `vue3` | Vue 3 + Vite | + vue-cursor-skills (separate install) |
|
|
336
|
+
| `node` | Node.js | + javascript-core, javascript-node |
|
|
337
|
+
|
|
338
|
+
For `vue3`, after kit init also run:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
npx vue-cursor-skills install
|
|
342
|
+
rsync -a .cursor/skills/ .agents/skills/
|
|
343
|
+
./scripts/sync-local-agent-skills.sh
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Memory MCP — Shared State Between Sessions
|
|
347
|
+
|
|
348
|
+
Each role starts a fresh session. Memory MCP persists orchestration state across sessions so you don't re-explain context every time.
|
|
349
|
+
|
|
350
|
+
**Standard entities to save:**
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
Change:add-bulk-export status: spec-approved, tasks: 0/7
|
|
354
|
+
Decision:export-format chosen: xlsx, reason: matches existing reports
|
|
355
|
+
Convention:api-errors use ApiError class, not raw Error
|
|
356
|
+
Handoff:add-bulk-export next_role: implementer, session_count: 1
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
At the start of each implementer/reviewer session, read relevant memory:
|
|
360
|
+
```
|
|
361
|
+
What do we know about Change:add-bulk-export?
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Amp Code — Deep Integration Notes
|
|
365
|
+
|
|
366
|
+
Amp is the **primary target** of this kit. It reads `.agents/skills/` and `AGENTS.md` without any sync step — your team commits `.agents/` and everyone gets the same orchestration behavior automatically.
|
|
367
|
+
|
|
368
|
+
**Amp-specific features used:**
|
|
369
|
+
|
|
370
|
+
| Feature | How the kit uses it |
|
|
371
|
+
|---------|-------------------|
|
|
372
|
+
| `AGENTS.md` subtree loading | Per-domain AGENTS.md in `openspec/` subtree |
|
|
373
|
+
| `.agents/skills/` | All orchestration + domain skills |
|
|
374
|
+
| `mcp.json` in skill dir | Lazy MCP loading (Memory only when needed) |
|
|
375
|
+
| Subagents | Explore and Review skills use forked subagents |
|
|
376
|
+
| Amp modes (rush/smart/deep) | Per-role model hints in AGENTS.md |
|
|
377
|
+
|
|
378
|
+
**Amp subagent in skill** (`.agents/skills/openspec-explore/SKILL.md`):
|
|
379
|
+
|
|
380
|
+
```yaml
|
|
381
|
+
---
|
|
382
|
+
name: openspec-explore
|
|
383
|
+
description: Enter explore mode — read-only thinking partner
|
|
384
|
+
disable-model-invocation: false
|
|
385
|
+
allowed-tools: Read, Bash
|
|
386
|
+
---
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Amp will run this skill as a subagent when invoked.
|
|
390
|
+
|
|
391
|
+
**Team workflow with Amp:**
|
|
392
|
+
|
|
393
|
+
1. Commit `.agents/` to git.
|
|
394
|
+
2. Team members clone — skills available immediately.
|
|
395
|
+
3. No `sync-local-agent-skills.sh` needed for Amp users.
|
|
396
|
+
4. Cursor/Claude Code users run sync once after clone.
|
|
397
|
+
|
|
398
|
+
## CLI Reference
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
npx agent-orchestrator-kit init [options]
|
|
402
|
+
--profile <name> Stack profile: generic | vue3 | node | python
|
|
403
|
+
--lang <code> Agent language: en | uk | ...
|
|
404
|
+
--name <name> Project name (default: directory name)
|
|
405
|
+
--force Overwrite existing files
|
|
406
|
+
|
|
407
|
+
npx agent-orchestrator-kit update
|
|
408
|
+
Updates kit-managed files, preserves project overlay
|
|
409
|
+
|
|
410
|
+
npx agent-orchestrator-kit sync [options]
|
|
411
|
+
--target <ide> cursor | claude | all (default: all)
|
|
412
|
+
Copies .agents/ to local IDE directories
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Directory Reference
|
|
416
|
+
|
|
417
|
+
```
|
|
418
|
+
.agents/ # Committed — source of truth for all IDEs
|
|
419
|
+
commands/ # /opsx:* command definitions
|
|
420
|
+
rules/ # Auto-applied rules for Cursor
|
|
421
|
+
skills/ # Skills for Cursor, Claude Code, Amp
|
|
422
|
+
orchestrator.yaml # Project pipeline config
|
|
423
|
+
|
|
424
|
+
.cursor/ # Local only — Cursor IDE runtime
|
|
425
|
+
skills/ # Synced from .agents/skills/
|
|
426
|
+
rules/ # Synced from .agents/rules/
|
|
427
|
+
memory.json # Memory MCP data
|
|
428
|
+
|
|
429
|
+
.claude/ # Local only — Claude Code runtime
|
|
430
|
+
skills/ # Synced from .agents/skills/
|
|
431
|
+
CLAUDE.md # Synced from root CLAUDE.md
|
|
432
|
+
|
|
433
|
+
.amp/ # Local only — Amp config
|
|
434
|
+
settings.json # MCP servers (manual or via amp mcp add)
|
|
435
|
+
|
|
436
|
+
AGENTS.md # Committed — Amp + Claude (AGENT.md fallback)
|
|
437
|
+
CLAUDE.md # Committed — synced to .claude/CLAUDE.md
|
|
438
|
+
openspec/ # Committed — spec-driven workflow
|
|
439
|
+
config.yaml # Project context for AI
|
|
440
|
+
specs/ # Source of truth after archive
|
|
441
|
+
changes/ # Active work
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## License
|
|
445
|
+
|
|
446
|
+
MIT © [Maksim Shevyakov](https://github.com/makshc2)
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { readFileSync, existsSync, mkdirSync, copyFileSync, readdirSync, statSync, writeFileSync } from 'fs';
|
|
5
|
+
import { join, dirname, basename } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { execSync } from 'child_process';
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const KIT_ROOT = join(__dirname, '..');
|
|
11
|
+
const KIT_VERSION = JSON.parse(readFileSync(join(KIT_ROOT, 'package.json'), 'utf-8')).version;
|
|
12
|
+
|
|
13
|
+
const log = {
|
|
14
|
+
info: (msg) => console.log(pc.cyan(' →'), msg),
|
|
15
|
+
ok: (msg) => console.log(pc.green(' ✓'), msg),
|
|
16
|
+
warn: (msg) => console.log(pc.yellow(' !'), msg),
|
|
17
|
+
err: (msg) => console.log(pc.red(' ✗'), msg),
|
|
18
|
+
title: (msg) => console.log(pc.bold(pc.white(`\n${msg}`))),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function copyDir(src, dest, opts = {}) {
|
|
22
|
+
const { overwrite = true, skip = [] } = opts;
|
|
23
|
+
if (!existsSync(src)) return;
|
|
24
|
+
mkdirSync(dest, { recursive: true });
|
|
25
|
+
for (const entry of readdirSync(src)) {
|
|
26
|
+
if (skip.includes(entry)) continue;
|
|
27
|
+
const srcPath = join(src, entry);
|
|
28
|
+
const destPath = join(dest, entry);
|
|
29
|
+
if (statSync(srcPath).isDirectory()) {
|
|
30
|
+
copyDir(srcPath, destPath, opts);
|
|
31
|
+
} else {
|
|
32
|
+
if (!overwrite && existsSync(destPath)) {
|
|
33
|
+
log.warn(`skip (exists): ${destPath}`);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
copyFileSync(srcPath, destPath);
|
|
37
|
+
log.ok(destPath.replace(process.cwd() + '/', ''));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function mergeGitignore(projectDir, lines) {
|
|
43
|
+
const gitignorePath = join(projectDir, '.gitignore');
|
|
44
|
+
let content = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf-8') : '';
|
|
45
|
+
let changed = false;
|
|
46
|
+
for (const line of lines) {
|
|
47
|
+
if (!content.includes(line)) {
|
|
48
|
+
content += `\n${line}`;
|
|
49
|
+
changed = true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (changed) {
|
|
53
|
+
writeFileSync(gitignorePath, content.trimStart());
|
|
54
|
+
log.ok('.gitignore updated');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolveTemplate(templateName, profile) {
|
|
59
|
+
const profilePath = join(KIT_ROOT, 'profiles', profile, templateName);
|
|
60
|
+
if (existsSync(profilePath)) return profilePath;
|
|
61
|
+
return join(KIT_ROOT, 'templates', templateName);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function applyPlaceholders(filePath, vars) {
|
|
65
|
+
if (!existsSync(filePath)) return;
|
|
66
|
+
let content = readFileSync(filePath, 'utf-8');
|
|
67
|
+
for (const [key, val] of Object.entries(vars)) {
|
|
68
|
+
content = content.replaceAll(`{{${key}}}`, val);
|
|
69
|
+
}
|
|
70
|
+
writeFileSync(filePath, content);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
program
|
|
74
|
+
.name('agent-orchestrator')
|
|
75
|
+
.description('Universal AI agent orchestration kit for Cursor, Claude Code, and Amp Code')
|
|
76
|
+
.version(KIT_VERSION);
|
|
77
|
+
|
|
78
|
+
program
|
|
79
|
+
.command('init')
|
|
80
|
+
.description('Install orchestrator kit into the current project')
|
|
81
|
+
.option('--profile <profile>', 'Stack profile: generic | vue3 | node | python', 'generic')
|
|
82
|
+
.option('--lang <lang>', 'Agent response language (en | uk | ...)', 'en')
|
|
83
|
+
.option('--name <name>', 'Project name (defaults to directory name)')
|
|
84
|
+
.option('--force', 'Overwrite existing files', false)
|
|
85
|
+
.action((opts) => {
|
|
86
|
+
const projectDir = process.cwd();
|
|
87
|
+
const projectName = opts.name || basename(projectDir);
|
|
88
|
+
|
|
89
|
+
log.title(`agent-orchestrator init v${KIT_VERSION}`);
|
|
90
|
+
log.info(`Project: ${projectName}`);
|
|
91
|
+
log.info(`Profile: ${opts.profile}`);
|
|
92
|
+
log.info(`Language: ${opts.lang}`);
|
|
93
|
+
|
|
94
|
+
const templateDir = join(KIT_ROOT, 'templates');
|
|
95
|
+
const profileDir = join(KIT_ROOT, 'profiles', opts.profile);
|
|
96
|
+
const vars = { PROJECT_NAME: projectName, LANG: opts.lang, KIT_VERSION };
|
|
97
|
+
|
|
98
|
+
log.title('Installing .agents/');
|
|
99
|
+
copyDir(join(templateDir, '.agents'), join(projectDir, '.agents'), { overwrite: opts.force });
|
|
100
|
+
if (existsSync(join(profileDir, '.agents'))) {
|
|
101
|
+
copyDir(join(profileDir, '.agents'), join(projectDir, '.agents'), { overwrite: opts.force });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
log.title('Installing scripts/');
|
|
105
|
+
copyDir(join(templateDir, 'scripts'), join(projectDir, 'scripts'), { overwrite: opts.force });
|
|
106
|
+
try {
|
|
107
|
+
execSync(`chmod +x ${join(projectDir, 'scripts', 'sync-local-agent-skills.sh')}`);
|
|
108
|
+
} catch {}
|
|
109
|
+
|
|
110
|
+
log.title('Installing root files');
|
|
111
|
+
for (const f of ['AGENTS.md', 'CLAUDE.md']) {
|
|
112
|
+
const src = resolveTemplate(f, opts.profile);
|
|
113
|
+
const dest = join(projectDir, f);
|
|
114
|
+
if (!opts.force && existsSync(dest)) {
|
|
115
|
+
log.warn(`skip (exists): ${f}`);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (existsSync(src)) {
|
|
119
|
+
copyFileSync(src, dest);
|
|
120
|
+
applyPlaceholders(dest, vars);
|
|
121
|
+
log.ok(f);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const orchSrc = resolveTemplate('orchestrator.yaml', opts.profile);
|
|
126
|
+
const orchDest = join(projectDir, '.agents', 'orchestrator.yaml');
|
|
127
|
+
if (!opts.force && existsSync(orchDest)) {
|
|
128
|
+
log.warn('skip (exists): .agents/orchestrator.yaml');
|
|
129
|
+
} else if (existsSync(orchSrc)) {
|
|
130
|
+
copyFileSync(orchSrc, orchDest);
|
|
131
|
+
applyPlaceholders(orchDest, vars);
|
|
132
|
+
log.ok('.agents/orchestrator.yaml');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
log.title('Updating .gitignore');
|
|
136
|
+
mergeGitignore(projectDir, ['.cursor', '.cursor/memory.json', '.amp/settings.json']);
|
|
137
|
+
|
|
138
|
+
log.title('Done');
|
|
139
|
+
log.ok(`agent-orchestrator-kit v${KIT_VERSION} installed`);
|
|
140
|
+
console.log(`
|
|
141
|
+
${pc.bold('Next steps:')}
|
|
142
|
+
1. Review ${pc.cyan('AGENTS.md')} and ${pc.cyan('.agents/orchestrator.yaml')}
|
|
143
|
+
2. Sync to your IDE:
|
|
144
|
+
${pc.cyan('./scripts/sync-local-agent-skills.sh')}
|
|
145
|
+
3. Install Memory MCP in .mcp.json (Cursor) / .amp/settings.json (Amp)
|
|
146
|
+
4. Start your first change:
|
|
147
|
+
${pc.cyan('/opsx:explore')}
|
|
148
|
+
`);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
program
|
|
152
|
+
.command('update')
|
|
153
|
+
.description('Update kit files without overwriting project overlay (orchestrator.yaml, project-conventions)')
|
|
154
|
+
.action(() => {
|
|
155
|
+
const projectDir = process.cwd();
|
|
156
|
+
const templateDir = join(KIT_ROOT, 'templates');
|
|
157
|
+
|
|
158
|
+
log.title(`agent-orchestrator update v${KIT_VERSION}`);
|
|
159
|
+
|
|
160
|
+
const KIT_FILES = [
|
|
161
|
+
'.agents/commands',
|
|
162
|
+
'.agents/rules',
|
|
163
|
+
'.agents/skills/agent-orchestration',
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
for (const rel of KIT_FILES) {
|
|
167
|
+
const src = join(templateDir, rel);
|
|
168
|
+
const dest = join(projectDir, rel);
|
|
169
|
+
if (existsSync(src)) {
|
|
170
|
+
copyDir(src, dest, { overwrite: true });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
for (const f of ['scripts/sync-local-agent-skills.sh']) {
|
|
175
|
+
const src = join(templateDir, f);
|
|
176
|
+
const dest = join(projectDir, f);
|
|
177
|
+
if (existsSync(src)) {
|
|
178
|
+
copyFileSync(src, dest);
|
|
179
|
+
log.ok(f);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
log.ok(`Updated to v${KIT_VERSION}`);
|
|
184
|
+
log.info('Run ./scripts/sync-local-agent-skills.sh to sync to local IDE');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
program
|
|
188
|
+
.command('sync')
|
|
189
|
+
.description('Sync .agents/ to local IDE directories (Cursor, Claude Code)')
|
|
190
|
+
.option('--target <target>', 'cursor | claude | amp | all', 'all')
|
|
191
|
+
.action((opts) => {
|
|
192
|
+
const projectDir = process.cwd();
|
|
193
|
+
|
|
194
|
+
log.title('agent-orchestrator sync');
|
|
195
|
+
|
|
196
|
+
const syncCursor = ['cursor', 'all'].includes(opts.target);
|
|
197
|
+
const syncClaude = ['claude', 'all'].includes(opts.target);
|
|
198
|
+
|
|
199
|
+
if (syncCursor) {
|
|
200
|
+
log.info('Syncing .agents/ → .cursor/');
|
|
201
|
+
copyDir(join(projectDir, '.agents', 'skills'), join(projectDir, '.cursor', 'skills'), { overwrite: true });
|
|
202
|
+
copyDir(join(projectDir, '.agents', 'rules'), join(projectDir, '.cursor', 'rules'), { overwrite: true });
|
|
203
|
+
|
|
204
|
+
const mcpExample = join(projectDir, '.agents', 'mcp.json.example');
|
|
205
|
+
const mcpDest = join(projectDir, '.mcp.json');
|
|
206
|
+
if (existsSync(mcpExample) && !existsSync(mcpDest)) {
|
|
207
|
+
copyFileSync(mcpExample, mcpDest);
|
|
208
|
+
log.ok('.mcp.json created from example');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (syncClaude) {
|
|
213
|
+
log.info('Syncing .agents/ → .claude/');
|
|
214
|
+
copyDir(join(projectDir, '.agents', 'skills'), join(projectDir, '.claude', 'skills'), { overwrite: true });
|
|
215
|
+
|
|
216
|
+
const claudeMd = join(projectDir, 'CLAUDE.md');
|
|
217
|
+
const claudeDir = join(projectDir, '.claude');
|
|
218
|
+
if (existsSync(claudeMd)) {
|
|
219
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
220
|
+
copyFileSync(claudeMd, join(claudeDir, 'CLAUDE.md'));
|
|
221
|
+
log.ok('.claude/CLAUDE.md');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
log.ok('Sync complete');
|
|
226
|
+
log.warn('.cursor/ and .claude/ are local only — not committed to git');
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
program.parse();
|