speexor 0.1.0 → 0.2.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/API-REFERENCE.md +96 -1
- package/ARCHITECTURE.md +84 -33
- package/BENCHMARKS.md +52 -0
- package/CHANGELOG.md +35 -4
- package/CODE-OF-CONDUCT.md +83 -83
- package/CONTRIBUTING.md +98 -98
- package/FAQ.md +105 -105
- package/GLOSSARY.md +33 -0
- package/LICENSE.md +21 -21
- package/PUBLISH.md +77 -77
- package/README.md +222 -8
- package/REFACTOR-LOG.md +40 -40
- package/ROADMAP.md +37 -15
- package/SECURITY-DEFAULTS.md +118 -0
- package/SECURITY.md +79 -79
- package/SUMMARY.md +31 -8
- package/TESTING.md +140 -140
- package/dist/{agent-5D3BVWNK.js → agent-D4BRWEOZ.js} +4 -4
- package/dist/agent-D4BRWEOZ.js.map +1 -0
- package/dist/{chunk-2F66BZYJ.js → chunk-2DX54KIM.js} +2 -2
- package/dist/chunk-2DX54KIM.js.map +1 -0
- package/dist/{chunk-B7WLHC4W.js → chunk-7VZHDGRQ.js} +2 -2
- package/dist/chunk-7VZHDGRQ.js.map +1 -0
- package/dist/{chunk-SXALZEOJ.js → chunk-AOFWQZWY.js} +2 -2
- package/dist/chunk-AOFWQZWY.js.map +1 -0
- package/dist/cli/index.js +4 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/plugins/index.js +1 -1
- package/docs/SETUP.md +94 -94
- package/docs/TROUBLESHOOTING.md +113 -113
- package/docs/adr/0001-record-architecture-decisions.md +44 -0
- package/docs/adr/0002-plugin-architecture.md +53 -0
- package/docs/adr/0003-recursive-task-decomposition.md +57 -0
- package/docs/adr/0004-local-first-security.md +58 -0
- package/docs/adr/0005-data-directory-layout.md +69 -0
- package/examples/basic.yaml +61 -61
- package/package.json +103 -102
- package/schema/config.schema.json +119 -119
- package/speexor.config.yaml.example +30 -30
- package/dist/agent-5D3BVWNK.js.map +0 -1
- package/dist/chunk-2F66BZYJ.js.map +0 -1
- package/dist/chunk-B7WLHC4W.js.map +0 -1
- package/dist/chunk-SXALZEOJ.js.map +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# ADR-0005: User-Home Data Directory Layout (~/.speexor/)
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
Speexor persists several kinds of local state: session data, task graphs, checkpoints, the decision log, extension caches, and secret references. Earlier drafts left the storage location implicit. A formal decision is needed on:
|
|
10
|
+
|
|
11
|
+
1. **Location:** Should data live in the project directory (`.speexor/`) or the user home directory (`~/.speexor/`)?
|
|
12
|
+
2. **Structure:** How should different data types (SQLite, JSON, binary checkpoints, vault references) be organized?
|
|
13
|
+
3. **Isolation:** How do we prevent state leakage between different projects managed by Speexor?
|
|
14
|
+
|
|
15
|
+
## Decision
|
|
16
|
+
|
|
17
|
+
### Location: ~/.speexor/ (User Home)
|
|
18
|
+
|
|
19
|
+
All persistent state lives under `~/.speexor/` in the user's home directory, not project-local. Each managed project gets a subdirectory keyed by a content-hash of the repository URL combined with a short project ID:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
~/.speexor/
|
|
23
|
+
├── 1a2b3c4d-my-project/ # Per-project directory (hash-projectId)
|
|
24
|
+
│ ├── task-graph.sqlite # Task graph DAG store (SQLite)
|
|
25
|
+
│ ├── decision-log.sqlite # Decision Log (SQLite, read-only history)
|
|
26
|
+
│ ├── checkpoints/ # Session checkpoint snapshots (JSON)
|
|
27
|
+
│ │ ├── checkpoint-abc.json
|
|
28
|
+
│ │ └── checkpoint-def.json
|
|
29
|
+
│ ├── extensions/ # Downloaded/cached extension manifests
|
|
30
|
+
│ └── vault-refs.json # References into OS keychain (never secrets)
|
|
31
|
+
├── registry-cache/ # Marketplace registry index cache
|
|
32
|
+
├── logs/ # Global orchestrator logs
|
|
33
|
+
└── lock # Process lock file (prevents concurrent instances)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Rationale for `~/.speexor/` over project-local:
|
|
37
|
+
|
|
38
|
+
- Data survives project directory deletion (user can delete a clone without losing the decision log).
|
|
39
|
+
- Multiple clones of the same repo share a single project directory (hash-based dedup).
|
|
40
|
+
- Cleaner user experience — no hidden directories scattered across the file system.
|
|
41
|
+
- Consistent with established patterns (`.aws/`, `.config/`, `.npm/`, etc.).
|
|
42
|
+
|
|
43
|
+
### Storage Formats
|
|
44
|
+
|
|
45
|
+
| Data Type | Format | Rationale |
|
|
46
|
+
|------------------|---------|------------------------------------------------|
|
|
47
|
+
| Task graph | SQLite | Relational queries on DAG nodes/edges |
|
|
48
|
+
| Decision log | SQLite | Searchable, filterable history |
|
|
49
|
+
| Checkpoints | JSON | Human-readable, debuggable snapshots |
|
|
50
|
+
| Extension cache | JSON | Simple manifest storage, no query pattern |
|
|
51
|
+
| Vault refs | JSON | Lightweight reference store (values in keychain)|
|
|
52
|
+
| Session state | JSON | Synchronous read/write for simplicity |
|
|
53
|
+
|
|
54
|
+
### Secrets Management
|
|
55
|
+
|
|
56
|
+
The `vault-refs.json` file contains only **references** (key names/paths) into the OS keychain. Actual secret values (API tokens, encryption keys) are stored via the OS keychain (macOS Keychain, Windows Credential Manager, Linux libsecret) and never written to disk in plaintext. The `secretsBackend` config option controls which backend is used.
|
|
57
|
+
|
|
58
|
+
### Process Lock
|
|
59
|
+
|
|
60
|
+
A `lock` file at `~/.speexor/lock` prevents multiple Speexor processes from operating on the same data directory simultaneously. The lock is advisory — it contains the PID and is cleaned up on graceful shutdown. Stale locks from crashes are automatically detected and cleared on startup.
|
|
61
|
+
|
|
62
|
+
## Consequences
|
|
63
|
+
|
|
64
|
+
- **Positive:** Data persists across project directory deletions; clean separation between projects.
|
|
65
|
+
- **Positive:** Hash-based project IDs prevent collisions and enable deduplication.
|
|
66
|
+
- **Positive:** SQLite for graph and decision log enables efficient queries vs. JSON scanning.
|
|
67
|
+
- **Negative:** User-home directory may not be writable in some locked-down enterprise environments (mitigation: `SPEEXOR_DATA_DIR` env var override).
|
|
68
|
+
- **Negative:** OS keychain dependency adds a setup step for headless/server environments.
|
|
69
|
+
- **Neutral:** Consistent with `speexor migrate-from-konduktor` migration path (FR-84).
|
package/examples/basic.yaml
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
# Speexor Configuration — Basic Example
|
|
2
|
-
# Agent Orchestrator for multi-AI coding agent orchestration
|
|
3
|
-
#
|
|
4
|
-
# Usage:
|
|
5
|
-
# 1. Save this file as speexor.config.yaml in your project root
|
|
6
|
-
# 2. Run `speexor start` to initialize and open the dashboard
|
|
7
|
-
# 3. Run `speexor agent spawn --task <issue-id>` to spawn an agent
|
|
8
|
-
|
|
9
|
-
version: "1"
|
|
10
|
-
|
|
11
|
-
projects:
|
|
12
|
-
# --- Single project, single agent ---
|
|
13
|
-
- name: brainclash
|
|
14
|
-
repository: https://github.com/superdevids/brainclash
|
|
15
|
-
provider:
|
|
16
|
-
primary: opencode
|
|
17
|
-
fallback:
|
|
18
|
-
- claude-code
|
|
19
|
-
- aider
|
|
20
|
-
concurrentLimit: 3
|
|
21
|
-
|
|
22
|
-
# Automated reactions to CI and PR events
|
|
23
|
-
reactions:
|
|
24
|
-
ci-failed:
|
|
25
|
-
auto: true
|
|
26
|
-
action: fix
|
|
27
|
-
retries: 3
|
|
28
|
-
escalateAfter: 30
|
|
29
|
-
changes-requested:
|
|
30
|
-
auto: true
|
|
31
|
-
action: fix
|
|
32
|
-
retries: 2
|
|
33
|
-
escalateAfter: 60
|
|
34
|
-
approved-and-green:
|
|
35
|
-
auto: false
|
|
36
|
-
action: notify
|
|
37
|
-
retries: 0
|
|
38
|
-
escalateAfter: 0
|
|
39
|
-
|
|
40
|
-
# --- Second project with different provider ---
|
|
41
|
-
- name: kata-netizen
|
|
42
|
-
repository: https://github.com/superdevids/kata-netizen
|
|
43
|
-
provider:
|
|
44
|
-
primary: claude-code
|
|
45
|
-
concurrentLimit: 2
|
|
46
|
-
reactions:
|
|
47
|
-
ci-failed:
|
|
48
|
-
auto: true
|
|
49
|
-
action: fix
|
|
50
|
-
retries: 3
|
|
51
|
-
escalateAfter: 30
|
|
52
|
-
changes-requested:
|
|
53
|
-
auto: true
|
|
54
|
-
action: fix
|
|
55
|
-
retries: 2
|
|
56
|
-
escalateAfter: 45
|
|
57
|
-
approved-and-green:
|
|
58
|
-
auto: false
|
|
59
|
-
action: notify
|
|
60
|
-
retries: 0
|
|
61
|
-
escalateAfter: 0
|
|
1
|
+
# Speexor Configuration — Basic Example
|
|
2
|
+
# Agent Orchestrator for multi-AI coding agent orchestration
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# 1. Save this file as speexor.config.yaml in your project root
|
|
6
|
+
# 2. Run `speexor start` to initialize and open the dashboard
|
|
7
|
+
# 3. Run `speexor agent spawn --task <issue-id>` to spawn an agent
|
|
8
|
+
|
|
9
|
+
version: "1"
|
|
10
|
+
|
|
11
|
+
projects:
|
|
12
|
+
# --- Single project, single agent ---
|
|
13
|
+
- name: brainclash
|
|
14
|
+
repository: https://github.com/superdevids/brainclash
|
|
15
|
+
provider:
|
|
16
|
+
primary: opencode
|
|
17
|
+
fallback:
|
|
18
|
+
- claude-code
|
|
19
|
+
- aider
|
|
20
|
+
concurrentLimit: 3
|
|
21
|
+
|
|
22
|
+
# Automated reactions to CI and PR events
|
|
23
|
+
reactions:
|
|
24
|
+
ci-failed:
|
|
25
|
+
auto: true
|
|
26
|
+
action: fix
|
|
27
|
+
retries: 3
|
|
28
|
+
escalateAfter: 30
|
|
29
|
+
changes-requested:
|
|
30
|
+
auto: true
|
|
31
|
+
action: fix
|
|
32
|
+
retries: 2
|
|
33
|
+
escalateAfter: 60
|
|
34
|
+
approved-and-green:
|
|
35
|
+
auto: false
|
|
36
|
+
action: notify
|
|
37
|
+
retries: 0
|
|
38
|
+
escalateAfter: 0
|
|
39
|
+
|
|
40
|
+
# --- Second project with different provider ---
|
|
41
|
+
- name: kata-netizen
|
|
42
|
+
repository: https://github.com/superdevids/kata-netizen
|
|
43
|
+
provider:
|
|
44
|
+
primary: claude-code
|
|
45
|
+
concurrentLimit: 2
|
|
46
|
+
reactions:
|
|
47
|
+
ci-failed:
|
|
48
|
+
auto: true
|
|
49
|
+
action: fix
|
|
50
|
+
retries: 3
|
|
51
|
+
escalateAfter: 30
|
|
52
|
+
changes-requested:
|
|
53
|
+
auto: true
|
|
54
|
+
action: fix
|
|
55
|
+
retries: 2
|
|
56
|
+
escalateAfter: 45
|
|
57
|
+
approved-and-green:
|
|
58
|
+
auto: false
|
|
59
|
+
action: notify
|
|
60
|
+
retries: 0
|
|
61
|
+
escalateAfter: 0
|
package/package.json
CHANGED
|
@@ -1,102 +1,103 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "speexor",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Speexor — Agent Orchestrator for multi-AI coding agent orchestration across repositories",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"module": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"bin": {
|
|
10
|
-
"speexor": "dist/cli/index.js"
|
|
11
|
-
},
|
|
12
|
-
"exports": {
|
|
13
|
-
".": {
|
|
14
|
-
"import": "./dist/index.js",
|
|
15
|
-
"types": "./dist/index.d.ts"
|
|
16
|
-
},
|
|
17
|
-
"./core": {
|
|
18
|
-
"import": "./dist/core/index.js",
|
|
19
|
-
"types": "./dist/core/index.d.ts"
|
|
20
|
-
},
|
|
21
|
-
"./cli": {
|
|
22
|
-
"import": "./dist/cli/index.js",
|
|
23
|
-
"types": "./dist/cli/index.d.ts"
|
|
24
|
-
},
|
|
25
|
-
"./plugins": {
|
|
26
|
-
"import": "./dist/plugins/index.js",
|
|
27
|
-
"types": "./dist/plugins/index.d.ts"
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"files": [
|
|
31
|
-
"dist",
|
|
32
|
-
"schema",
|
|
33
|
-
"docs",
|
|
34
|
-
"*.md",
|
|
35
|
-
"examples",
|
|
36
|
-
"speexor.config.yaml.example"
|
|
37
|
-
],
|
|
38
|
-
"scripts": {
|
|
39
|
-
"build": "tsup",
|
|
40
|
-
"dev": "tsup --watch",
|
|
41
|
-
"test": "vitest run",
|
|
42
|
-
"test:watch": "vitest",
|
|
43
|
-
"test:coverage": "vitest run --coverage",
|
|
44
|
-
"typecheck": "tsc --noEmit",
|
|
45
|
-
"lint": "biome check src/",
|
|
46
|
-
"lint:fix": "biome check --write src/",
|
|
47
|
-
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
|
|
48
|
-
},
|
|
49
|
-
"dependencies": {
|
|
50
|
-
"
|
|
51
|
-
"chalk": "^5.3.0",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"@
|
|
66
|
-
"@types/
|
|
67
|
-
"@
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "speexor",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Speexor — Agent Orchestrator for multi-AI coding agent orchestration across repositories",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"speexor": "dist/cli/index.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./core": {
|
|
18
|
+
"import": "./dist/core/index.js",
|
|
19
|
+
"types": "./dist/core/index.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./cli": {
|
|
22
|
+
"import": "./dist/cli/index.js",
|
|
23
|
+
"types": "./dist/cli/index.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./plugins": {
|
|
26
|
+
"import": "./dist/plugins/index.js",
|
|
27
|
+
"types": "./dist/plugins/index.d.ts"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"schema",
|
|
33
|
+
"docs",
|
|
34
|
+
"*.md",
|
|
35
|
+
"examples",
|
|
36
|
+
"speexor.config.yaml.example"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup",
|
|
40
|
+
"dev": "tsup --watch",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:watch": "vitest",
|
|
43
|
+
"test:coverage": "vitest run --coverage",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"lint": "biome check src/",
|
|
46
|
+
"lint:fix": "biome check --write src/",
|
|
47
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"better-sqlite3": "^11.10.0",
|
|
51
|
+
"chalk": "^5.3.0",
|
|
52
|
+
"commander": "^12.0.0",
|
|
53
|
+
"conf": "^12.0.0",
|
|
54
|
+
"dayjs": "^1.11.0",
|
|
55
|
+
"debug": "^4.3.0",
|
|
56
|
+
"eventemitter3": "^5.0.0",
|
|
57
|
+
"execa": "^9.0.0",
|
|
58
|
+
"globby": "^14.0.0",
|
|
59
|
+
"node-emoji": "^2.1.0",
|
|
60
|
+
"ora": "^8.0.0",
|
|
61
|
+
"yaml": "^2.5.0",
|
|
62
|
+
"zod": "^3.23.0"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@biomejs/biome": "^2.5.1",
|
|
66
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
67
|
+
"@types/debug": "^4.1.0",
|
|
68
|
+
"@types/node": "^26.0.1",
|
|
69
|
+
"@vitest/coverage-v8": "^2.1.9",
|
|
70
|
+
"tsup": "^8.3.0",
|
|
71
|
+
"typescript": "^5.7.0",
|
|
72
|
+
"vite": "^8.1.0",
|
|
73
|
+
"vitest": "^2.1.0"
|
|
74
|
+
},
|
|
75
|
+
"keywords": [
|
|
76
|
+
"orchestrator",
|
|
77
|
+
"ai-agent",
|
|
78
|
+
"agent-orchestration",
|
|
79
|
+
"coding-agent",
|
|
80
|
+
"claude-code",
|
|
81
|
+
"opencode",
|
|
82
|
+
"aider",
|
|
83
|
+
"codex",
|
|
84
|
+
"multi-agent",
|
|
85
|
+
"speexor"
|
|
86
|
+
],
|
|
87
|
+
"publishConfig": {
|
|
88
|
+
"access": "public"
|
|
89
|
+
},
|
|
90
|
+
"preferGlobal": true,
|
|
91
|
+
"repository": {
|
|
92
|
+
"type": "git",
|
|
93
|
+
"url": "git+https://github.com/superdevids/speexor.git"
|
|
94
|
+
},
|
|
95
|
+
"bugs": {
|
|
96
|
+
"url": "https://github.com/superdevids/speexor/issues"
|
|
97
|
+
},
|
|
98
|
+
"homepage": "https://github.com/superdevids/speexor#readme",
|
|
99
|
+
"license": "MIT",
|
|
100
|
+
"engines": {
|
|
101
|
+
"node": ">=18.0.0"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -1,119 +1,119 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"$id": "https://speexjs.dev/schemas/speexor-config.json",
|
|
4
|
-
"title": "Speexor Configuration",
|
|
5
|
-
"description": "Configuration schema for Speexor — Agent Orchestrator",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"required": ["version", "projects"],
|
|
8
|
-
"properties": {
|
|
9
|
-
"version": {
|
|
10
|
-
"type": "string",
|
|
11
|
-
"enum": ["1"],
|
|
12
|
-
"description": "Config schema version"
|
|
13
|
-
},
|
|
14
|
-
"projects": {
|
|
15
|
-
"type": "array",
|
|
16
|
-
"minItems": 1,
|
|
17
|
-
"items": {
|
|
18
|
-
"type": "object",
|
|
19
|
-
"required": ["name", "repository", "provider"],
|
|
20
|
-
"properties": {
|
|
21
|
-
"name": {
|
|
22
|
-
"type": "string",
|
|
23
|
-
"description": "Project display name"
|
|
24
|
-
},
|
|
25
|
-
"repository": {
|
|
26
|
-
"type": "string",
|
|
27
|
-
"description": "Git repository URL or local path"
|
|
28
|
-
},
|
|
29
|
-
"path": {
|
|
30
|
-
"type": "string",
|
|
31
|
-
"description": "Local path override for repository"
|
|
32
|
-
},
|
|
33
|
-
"branch": {
|
|
34
|
-
"type": "string",
|
|
35
|
-
"description": "Default base branch",
|
|
36
|
-
"default": "main"
|
|
37
|
-
},
|
|
38
|
-
"provider": {
|
|
39
|
-
"type": "object",
|
|
40
|
-
"required": ["primary"],
|
|
41
|
-
"properties": {
|
|
42
|
-
"primary": {
|
|
43
|
-
"type": "string",
|
|
44
|
-
"enum": ["opencode", "claude-code", "aider", "codex"],
|
|
45
|
-
"description": "Primary AI coding agent"
|
|
46
|
-
},
|
|
47
|
-
"fallback": {
|
|
48
|
-
"type": "array",
|
|
49
|
-
"items": {
|
|
50
|
-
"type": "string",
|
|
51
|
-
"enum": ["opencode", "claude-code", "aider", "codex"]
|
|
52
|
-
},
|
|
53
|
-
"description": "Fallback agents in priority order"
|
|
54
|
-
},
|
|
55
|
-
"concurrentLimit": {
|
|
56
|
-
"type": "integer",
|
|
57
|
-
"minimum": 1,
|
|
58
|
-
"maximum": 20,
|
|
59
|
-
"description": "Maximum parallel agents for this project"
|
|
60
|
-
},
|
|
61
|
-
"costLimit": {
|
|
62
|
-
"type": "integer",
|
|
63
|
-
"minimum": 0,
|
|
64
|
-
"description": "Cost limit in cents per session"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
"reactions": {
|
|
69
|
-
"type": "object",
|
|
70
|
-
"properties": {
|
|
71
|
-
"ci-failed": { "$ref": "#/definitions/reactionRule" },
|
|
72
|
-
"changes-requested": { "$ref": "#/definitions/reactionRule" },
|
|
73
|
-
"approved-and-green": { "$ref": "#/definitions/reactionRule" }
|
|
74
|
-
},
|
|
75
|
-
"description": "Reaction rules for CI/PR events"
|
|
76
|
-
},
|
|
77
|
-
"plugins": {
|
|
78
|
-
"type": "object",
|
|
79
|
-
"properties": {
|
|
80
|
-
"tracker": { "type": "string" },
|
|
81
|
-
"scm": { "type": "string" },
|
|
82
|
-
"runtime": { "type": "string" },
|
|
83
|
-
"notifier": { "type": "string" }
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
"definitions": {
|
|
91
|
-
"reactionRule": {
|
|
92
|
-
"type": "object",
|
|
93
|
-
"required": ["auto", "action"],
|
|
94
|
-
"properties": {
|
|
95
|
-
"auto": {
|
|
96
|
-
"type": "boolean",
|
|
97
|
-
"description": "Auto-trigger reaction when event occurs"
|
|
98
|
-
},
|
|
99
|
-
"action": {
|
|
100
|
-
"type": "string",
|
|
101
|
-
"enum": ["fix", "notify", "escalate", "skip"],
|
|
102
|
-
"description": "Action to take when reaction triggers"
|
|
103
|
-
},
|
|
104
|
-
"retries": {
|
|
105
|
-
"type": "integer",
|
|
106
|
-
"minimum": 0,
|
|
107
|
-
"maximum": 10,
|
|
108
|
-
"description": "Number of retry attempts"
|
|
109
|
-
},
|
|
110
|
-
"escalateAfter": {
|
|
111
|
-
"type": "integer",
|
|
112
|
-
"minimum": 1,
|
|
113
|
-
"maximum": 1440,
|
|
114
|
-
"description": "Minutes before escalating to human"
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://speexjs.dev/schemas/speexor-config.json",
|
|
4
|
+
"title": "Speexor Configuration",
|
|
5
|
+
"description": "Configuration schema for Speexor — Agent Orchestrator",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["version", "projects"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"version": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"enum": ["1"],
|
|
12
|
+
"description": "Config schema version"
|
|
13
|
+
},
|
|
14
|
+
"projects": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"minItems": 1,
|
|
17
|
+
"items": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"required": ["name", "repository", "provider"],
|
|
20
|
+
"properties": {
|
|
21
|
+
"name": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Project display name"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "Git repository URL or local path"
|
|
28
|
+
},
|
|
29
|
+
"path": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "Local path override for repository"
|
|
32
|
+
},
|
|
33
|
+
"branch": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Default base branch",
|
|
36
|
+
"default": "main"
|
|
37
|
+
},
|
|
38
|
+
"provider": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"required": ["primary"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"primary": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"enum": ["opencode", "claude-code", "aider", "codex"],
|
|
45
|
+
"description": "Primary AI coding agent"
|
|
46
|
+
},
|
|
47
|
+
"fallback": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"items": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"enum": ["opencode", "claude-code", "aider", "codex"]
|
|
52
|
+
},
|
|
53
|
+
"description": "Fallback agents in priority order"
|
|
54
|
+
},
|
|
55
|
+
"concurrentLimit": {
|
|
56
|
+
"type": "integer",
|
|
57
|
+
"minimum": 1,
|
|
58
|
+
"maximum": 20,
|
|
59
|
+
"description": "Maximum parallel agents for this project"
|
|
60
|
+
},
|
|
61
|
+
"costLimit": {
|
|
62
|
+
"type": "integer",
|
|
63
|
+
"minimum": 0,
|
|
64
|
+
"description": "Cost limit in cents per session"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"reactions": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"properties": {
|
|
71
|
+
"ci-failed": { "$ref": "#/definitions/reactionRule" },
|
|
72
|
+
"changes-requested": { "$ref": "#/definitions/reactionRule" },
|
|
73
|
+
"approved-and-green": { "$ref": "#/definitions/reactionRule" }
|
|
74
|
+
},
|
|
75
|
+
"description": "Reaction rules for CI/PR events"
|
|
76
|
+
},
|
|
77
|
+
"plugins": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"properties": {
|
|
80
|
+
"tracker": { "type": "string" },
|
|
81
|
+
"scm": { "type": "string" },
|
|
82
|
+
"runtime": { "type": "string" },
|
|
83
|
+
"notifier": { "type": "string" }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"definitions": {
|
|
91
|
+
"reactionRule": {
|
|
92
|
+
"type": "object",
|
|
93
|
+
"required": ["auto", "action"],
|
|
94
|
+
"properties": {
|
|
95
|
+
"auto": {
|
|
96
|
+
"type": "boolean",
|
|
97
|
+
"description": "Auto-trigger reaction when event occurs"
|
|
98
|
+
},
|
|
99
|
+
"action": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"enum": ["fix", "notify", "escalate", "skip"],
|
|
102
|
+
"description": "Action to take when reaction triggers"
|
|
103
|
+
},
|
|
104
|
+
"retries": {
|
|
105
|
+
"type": "integer",
|
|
106
|
+
"minimum": 0,
|
|
107
|
+
"maximum": 10,
|
|
108
|
+
"description": "Number of retry attempts"
|
|
109
|
+
},
|
|
110
|
+
"escalateAfter": {
|
|
111
|
+
"type": "integer",
|
|
112
|
+
"minimum": 1,
|
|
113
|
+
"maximum": 1440,
|
|
114
|
+
"description": "Minutes before escalating to human"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|