@delorenj/pjangler 1.2.18 → 1.2.21
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/dist/index.js +884 -295
- package/dist/mcp-server.js +892 -303
- package/package.json +8 -2
- package/templates/commonproject/AGENTS.md +3 -3
- package/templates/commonproject/README.md +11 -12
- package/templates/commonproject/copier.yml +11 -31
- package/templates/commonproject/template/.agents/hooks/README.md +13 -26
- package/templates/commonproject/template/.agents/hooks/lib/local-config.sh +4 -14
- package/templates/commonproject/template/.agents/hooks/sync.py +5 -6
- package/templates/commonproject/template/.agents/local.example.json +2 -8
- package/templates/commonproject/template/.agents/skills.json +6 -0
- package/templates/commonproject/template/.project.json.jinja +9 -13
- package/templates/commonproject/template/mise.toml.jinja +9 -16
- package/templates/hermes-agent/README.md +9 -9
- package/templates/hermes-agent/config.example.toml +1 -66
- package/templates/hermes-agent/copier.yml +4 -3
- package/templates/hermes-agent/docs/architecture.md +9 -12
- package/templates/hermes-agent/docs/fleet-control-plane/README.md +1 -1
- package/templates/hermes-agent/docs/operations.md +6 -5
- package/templates/hermes-agent/docs/sentinel/README.md +9 -7
- package/templates/hermes-agent/docs/sentinel/architecture.md +1 -2
- package/templates/hermes-agent/docs/sentinel/development.md +12 -13
- package/templates/hermes-agent/docs/sentinel/providers.md +34 -15
- package/templates/hermes-agent/install-local.sh +15 -14
- package/templates/hermes-agent/runtime-scaffold/README.md +1 -1
- package/templates/hermes-agent/runtime-scaffold/bloodbank-consumer.py +46 -14
- package/templates/hermes-agent/runtime-scaffold/memories/MEMORY.md +2 -2
- package/templates/hermes-agent/scripts/fleet-sync.sh +1 -64
- package/templates/hermes-agent/template/.gitignore.jinja +0 -2
- package/templates/hermes-agent/template/.runtime-scaffold/README.md +1 -1
- package/templates/hermes-agent/template/.runtime-scaffold/bloodbank-consumer.py +43 -9
- package/templates/hermes-agent/template/.runtime-scaffold/memories/MEMORY.md +2 -2
- package/templates/hermes-agent/template/.scripts/01-config.sh +0 -1
- package/templates/hermes-agent/template/.scripts/05-fleet-env.sh +0 -9
- package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +3 -22
- package/templates/hermes-agent/template/.scripts/20-runtime-repo.sh +0 -22
- package/templates/hermes-agent/template/.scripts/40-plane.sh +51 -0
- package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +59 -21
- package/templates/hermes-agent/template/.scripts/60-bloodbank.sh +2 -1
- package/templates/hermes-agent/template/.scripts/70-systemd.sh +1 -10
- package/templates/hermes-agent/template/.scripts/_lib.sh +3 -61
- package/templates/hermes-agent/template/.scripts/config.example.toml +0 -5
- package/templates/hermes-agent/template/.scripts/heartbeat.sh +33 -66
- package/templates/hermes-agent/template/.scripts/lib/ticket-provider.sh +5 -9
- package/templates/hermes-agent/template/.scripts/momo-wip-lock.py +137 -0
- package/templates/hermes-agent/template/.scripts/providers/linear.sh +176 -0
- package/templates/hermes-agent/template/.scripts/providers/plane.sh +9 -29
- package/templates/hermes-agent/template/.scripts/sentinel/docs/autonomous-delegated-review.md +2 -2
- package/templates/hermes-agent/template/.scripts/sentinel/docs/continuous-ticket-orchestration.md +1 -33
- package/templates/hermes-agent/template/.scripts/sentinel.prompt.md.jinja +22 -27
- package/templates/hermes-agent/template/SOUL.md.jinja +49 -30
- package/templates/hermes-agent/template/role.yaml.jinja +35 -4
- package/templates/hermes-agent/tests/test_bloodbank_consumer_contract.py +138 -0
- package/templates/commonproject/template/.mise/scripts/link-project-skills-to-clis.sh +0 -110
- package/templates/commonproject/template/.mise/scripts/unlink-project-skills-from-clis.sh +0 -45
- package/templates/hermes-agent/docs/bloodbank-gateway.md +0 -57
- package/templates/hermes-agent/docs/fleet-control-plane/n8n-service-hub.md +0 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delorenj/pjangler",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.21",
|
|
4
4
|
"description": "Project subsystem bootstrapper CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
"start": "node dist/index.js",
|
|
24
24
|
"mcp": "node dist/mcp-server.js",
|
|
25
25
|
"typecheck": "tsc --noEmit",
|
|
26
|
-
"test": "node tests/parity-migrate-regressions.mjs && node tests/mcp-catalog-regressions.mjs && node tests/mcp-server-regressions.mjs && node tests/project-registry-regressions.mjs",
|
|
26
|
+
"test": "node tests/parity-migrate-regressions.mjs && node tests/mcp-catalog-regressions.mjs && node tests/mcp-server-regressions.mjs && node tests/project-registry-regressions.mjs && node tests/pg-registry-regressions.mjs",
|
|
27
|
+
"migrate:up": "node-pg-migrate --migrations-dir migrations up",
|
|
28
|
+
"migrate:down": "node-pg-migrate --migrations-dir migrations down",
|
|
29
|
+
"migrate:create": "node-pg-migrate --migrations-dir migrations create",
|
|
27
30
|
"prepublishOnly": "npm run build"
|
|
28
31
|
},
|
|
29
32
|
"keywords": [
|
|
@@ -39,12 +42,15 @@
|
|
|
39
42
|
"@clack/prompts": "^1.4.0",
|
|
40
43
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
44
|
"commander": "^14.0.2",
|
|
45
|
+
"pg": "^8.16.0",
|
|
42
46
|
"yaml": "^2.9.0",
|
|
43
47
|
"zod": "^4.4.3"
|
|
44
48
|
},
|
|
45
49
|
"devDependencies": {
|
|
46
50
|
"@types/node": "^25.9.1",
|
|
51
|
+
"@types/pg": "^8.15.0",
|
|
47
52
|
"esbuild": "^0.25.0",
|
|
53
|
+
"node-pg-migrate": "^8.0.0",
|
|
48
54
|
"typescript": "^5"
|
|
49
55
|
}
|
|
50
56
|
}
|
|
@@ -20,7 +20,7 @@ CommonProject/
|
|
|
20
20
|
│ ├── .agentvibes/ # AgentVibes config
|
|
21
21
|
│ ├── .mise/tasks/ # File-based mise tasks
|
|
22
22
|
│ ├── .scripts/ # Post-generation utilities
|
|
23
|
-
│ │ └── setup-plane.py # Creates
|
|
23
|
+
│ │ └── setup-plane.py # Creates Plane project + ticket_provider block in .project.json
|
|
24
24
|
│ ├── AGENTS.md.jinja # Generated project's agent SSOT
|
|
25
25
|
│ ├── CLAUDE.md # Symlink → AGENTS.md
|
|
26
26
|
│ ├── GEMINI.md # Symlink → AGENTS.md
|
|
@@ -46,7 +46,7 @@ Root-level files describe the template itself. Files in `template/` are what Cop
|
|
|
46
46
|
Only two questions asked: `project_name` and `project_description`. Everything else is derived or automated:
|
|
47
47
|
- `project_slug` derived from project_name
|
|
48
48
|
- `user_name` / `user_skill_level` hardcoded for BMAD config
|
|
49
|
-
-
|
|
49
|
+
- Plane project created via API in post-generation task
|
|
50
50
|
- .gitignore copied from ~/.config/git/ignore
|
|
51
51
|
- git init + initial commit run automatically
|
|
52
52
|
|
|
@@ -55,7 +55,7 @@ Only two questions asked: `project_name` and `project_description`. Everything e
|
|
|
55
55
|
After rendering, Copier automatically:
|
|
56
56
|
1. Copies .gitignore from ~/.config/git/ignore
|
|
57
57
|
2. Makes scripts executable
|
|
58
|
-
3. Runs setup-plane.py (creates
|
|
58
|
+
3. Runs setup-plane.py (creates Plane project, writes the ticket_provider block in .project.json)
|
|
59
59
|
4. Runs git init + git add -A + git commit
|
|
60
60
|
|
|
61
61
|
### BMAD System
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# CommonProject
|
|
2
2
|
|
|
3
|
-
Copier template for creating new 33GOD ecosystem components with BMAD methodology, ticket
|
|
3
|
+
Copier template for creating new 33GOD ecosystem components with BMAD methodology, Plane ticket enforcement, and multi-agent development tooling.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Language Support**: Python, TypeScript, Rust
|
|
8
8
|
- **Event-Driven Architecture**: Optional [Bloodbank](https://github.com/delorenj/Bloodbank) integration
|
|
9
|
-
- **
|
|
10
|
-
- **Ticket Enforcement**: Git hooks enforce
|
|
9
|
+
- **Plane Integration**: `.project.json` for ticket management and project config
|
|
10
|
+
- **Ticket Enforcement**: Git hooks enforce Plane ticket requirements
|
|
11
11
|
- [TODO] **BMAD Integration**: Full BMAD methodology structure by auto running `npx bmad-method@latest install`
|
|
12
12
|
- [TODO] Multiple-choice selection for different workflows: BMAD, GSD, GoogleAgentSkills, None.
|
|
13
13
|
- **Containerization**: Optional Docker + Docker Compose
|
|
@@ -25,7 +25,7 @@ uv tool install copier
|
|
|
25
25
|
# Or with pip
|
|
26
26
|
pip install copier
|
|
27
27
|
|
|
28
|
-
# Set up
|
|
28
|
+
# Set up Plane API key (for automated project creation)
|
|
29
29
|
export PLANE_API_KEY="your-plane-api-key"
|
|
30
30
|
OR
|
|
31
31
|
[TODO] export PLANE_API_KEY=op://VaultName/Key/Field
|
|
@@ -36,14 +36,14 @@ OR
|
|
|
36
36
|
|
|
37
37
|
### Option 1: Automated Init (Recommended)
|
|
38
38
|
|
|
39
|
-
[TODO] One command handles everything:
|
|
39
|
+
[TODO] One command handles everything: Plane project creation + Copier template:
|
|
40
40
|
|
|
41
41
|
> TASK - Implement the following:
|
|
42
42
|
> Currently, I have to run `copier copy --trust ~/code CommonProject .` globally, or `mise run init-project` while in the CommonProject source dir - but this is not ideal.
|
|
43
43
|
> I would rather run `commonProject .` globally.
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
# Interactive wizard - creates
|
|
46
|
+
# Interactive wizard - creates Plane project automatically
|
|
47
47
|
mise run init-project
|
|
48
48
|
|
|
49
49
|
# Or non-interactive (uses defaults)
|
|
@@ -56,7 +56,7 @@ mise run init-project-non-interactive
|
|
|
56
56
|
The wizard will:
|
|
57
57
|
|
|
58
58
|
1. Ask for project details (name, description, type)
|
|
59
|
-
2. Create
|
|
59
|
+
2. Create the Plane project automatically
|
|
60
60
|
3. Run Copier with all answers pre-filled
|
|
61
61
|
4. Output next steps
|
|
62
62
|
|
|
@@ -83,10 +83,9 @@ The template asks for:
|
|
|
83
83
|
- **Project Slug**: Directory/package name (auto-generated from name)
|
|
84
84
|
- **Description**: One-sentence project description
|
|
85
85
|
|
|
86
|
-
###
|
|
86
|
+
### Plane Integration
|
|
87
87
|
|
|
88
|
-
- **
|
|
89
|
-
- **Workspace**: Provider workspace slug when applicable (Plane default: 33god)
|
|
88
|
+
- **Workspace**: Plane workspace slug (default: 33god)
|
|
90
89
|
- **Project Name**
|
|
91
90
|
- **Project Identifier**: 2+ character ticket prefix (e.g., HOLO, VERN)
|
|
92
91
|
|
|
@@ -111,10 +110,10 @@ The template asks for:
|
|
|
111
110
|
git commit -m "Initial commit from template"
|
|
112
111
|
```
|
|
113
112
|
|
|
114
|
-
3. **Create
|
|
113
|
+
3. **Create Plane Ticket**
|
|
115
114
|
|
|
116
115
|
```bash
|
|
117
|
-
# Create or
|
|
116
|
+
# Create ticket in Plane (or it was already created for you!)
|
|
118
117
|
# Move to "In Progress"
|
|
119
118
|
git checkout -b <IDENTIFIER>-123-initial-setup
|
|
120
119
|
```
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# Generic base project template. Creates a project skeleton with:
|
|
5
5
|
# - BMAD methodology (pre-initialized)
|
|
6
|
-
# -
|
|
6
|
+
# - Plane project (auto-created in 33god workspace)
|
|
7
7
|
# - mise environment management
|
|
8
8
|
# - CLI coder configs (Claude, Codex, Gemini, etc.)
|
|
9
9
|
|
|
@@ -30,15 +30,16 @@ project_description:
|
|
|
30
30
|
help: One-line description
|
|
31
31
|
default: ""
|
|
32
32
|
|
|
33
|
-
# Ticket board provider for this project.
|
|
34
|
-
#
|
|
35
|
-
# persisted into .project.json so it is
|
|
36
|
-
# the hermes-agent template's agents.
|
|
33
|
+
# Ticket board provider for this project. The board itself is created by
|
|
34
|
+
# init-project.sh (create-plane-project.sh) BEFORE copier runs; its identity is
|
|
35
|
+
# threaded back in via plane_* below and persisted into .project.json so it is
|
|
36
|
+
# the single source of truth shared with the hermes-agent template's agents.
|
|
37
37
|
ticket_provider:
|
|
38
38
|
type: str
|
|
39
39
|
help: Ticket board provider this project's board lives in
|
|
40
40
|
default: plane
|
|
41
41
|
choices:
|
|
42
|
+
Linear: linear
|
|
42
43
|
Plane: plane
|
|
43
44
|
Trello: trello
|
|
44
45
|
|
|
@@ -49,7 +50,8 @@ project_slug:
|
|
|
49
50
|
default: "{{ project_name | lower | replace(' ', '-') | replace('_', '-') }}"
|
|
50
51
|
when: false
|
|
51
52
|
|
|
52
|
-
#
|
|
53
|
+
# Board binding — supplied by init-project.sh's --data-file after the board is
|
|
54
|
+
# created. Defaults keep a bare `copier copy` rendering valid (empty binding).
|
|
53
55
|
plane_workspace:
|
|
54
56
|
type: str
|
|
55
57
|
default: "33god"
|
|
@@ -70,27 +72,6 @@ plane_base:
|
|
|
70
72
|
default: "https://plane.delo.sh"
|
|
71
73
|
when: false
|
|
72
74
|
|
|
73
|
-
# Provider-agnostic board binding — supplied by pjangler's --data values after
|
|
74
|
-
# the board is created or linked. Defaults keep a bare `copier copy` rendering
|
|
75
|
-
# valid, and fall back to the legacy plane_* aliases above. Board URLs are
|
|
76
|
-
# derived from provider/workspace/board_id and are intentionally not persisted.
|
|
77
|
-
board_id:
|
|
78
|
-
type: str
|
|
79
|
-
default: "{{ plane_project_id }}"
|
|
80
|
-
when: false
|
|
81
|
-
|
|
82
|
-
# Deprecated no-op accepted so older pjangler/CommonProject callers do not fail
|
|
83
|
-
# when they still pass `--data board_url=...`.
|
|
84
|
-
board_url:
|
|
85
|
-
type: str
|
|
86
|
-
default: ""
|
|
87
|
-
when: false
|
|
88
|
-
|
|
89
|
-
ticket_workspace:
|
|
90
|
-
type: str
|
|
91
|
-
default: "{{ plane_workspace if ticket_provider == 'plane' else '' }}"
|
|
92
|
-
when: false
|
|
93
|
-
|
|
94
75
|
# Drives conditional blocks in rendered files (e.g. _.python.venv in mise.toml).
|
|
95
76
|
# Not asked interactively; init-project.sh can override via --data-file.
|
|
96
77
|
primary_language:
|
|
@@ -109,8 +90,9 @@ agent_hooks_layer:
|
|
|
109
90
|
default: true
|
|
110
91
|
when: false
|
|
111
92
|
|
|
112
|
-
# When agent_hooks_layer is false, omit the project-scoped hook tree
|
|
113
|
-
#
|
|
93
|
+
# When agent_hooks_layer is false, omit only the project-scoped hook tree. The
|
|
94
|
+
# skills manifest stays — sync-skills.py writes project-local CLI dirs and is safe
|
|
95
|
+
# even on machines that already run a global ~/.agents/hooks install.
|
|
114
96
|
# The `.copier-noop-never-matches` sentinel keeps every pattern non-empty when the
|
|
115
97
|
# layer is enabled, which copier requires.
|
|
116
98
|
_exclude:
|
|
@@ -124,8 +106,6 @@ _exclude:
|
|
|
124
106
|
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/hooks{% endif %}"
|
|
125
107
|
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/hooks/**{% endif %}"
|
|
126
108
|
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/local.example.json{% endif %}"
|
|
127
|
-
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.mise/scripts/link-project-skills-to-clis.sh{% endif %}"
|
|
128
|
-
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.mise/scripts/unlink-project-skills-from-clis.sh{% endif %}"
|
|
129
109
|
|
|
130
110
|
# --- Post-generation tasks ---
|
|
131
111
|
#
|
|
@@ -15,6 +15,7 @@ master writes zero bytes).
|
|
|
15
15
|
mise run hooks-sync # fan out the master -> claude + codex + hermes
|
|
16
16
|
mise run hooks-check # drift gate (read-only; used in CI)
|
|
17
17
|
mise run hooks-uninstall # remove codex + hermes injections
|
|
18
|
+
mise run skills-sync # sync .agents/skills.json -> local CLI skill dirs
|
|
18
19
|
mise run hindsight-setup # one-time: pull the shared CAF Hindsight key into .env
|
|
19
20
|
```
|
|
20
21
|
|
|
@@ -70,8 +71,7 @@ Copy [`.agents/local.example.json`](../local.example.json) → `.agents/local.js
|
|
|
70
71
|
"hooks": {
|
|
71
72
|
"disabled": ["hindsight-recall"], // hook ids — skipped at runtime, ALL agents
|
|
72
73
|
"disabled_agents": ["codex"] // claude|codex|hermes — codex/hermes injection skipped/removed
|
|
73
|
-
}
|
|
74
|
-
"skills": { "disabled": ["bmad-help"] } // skill dir names — not symlinked for you
|
|
74
|
+
}
|
|
75
75
|
}
|
|
76
76
|
```
|
|
77
77
|
|
|
@@ -83,32 +83,18 @@ Copy [`.agents/local.example.json`](../local.example.json) → `.agents/local.js
|
|
|
83
83
|
- **Disabled agents** are enforced at **install** time (codex/hermes injection is
|
|
84
84
|
skipped, and removed if previously installed). `CAF_HOOKS_SKIP_CODEX=1` is an
|
|
85
85
|
env shortcut for `disabled_agents:["codex"]`.
|
|
86
|
-
-
|
|
86
|
+
## Skill fan-out — `.agents/skills.json` → each CLI
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
`.agents/skills.json` is the project's skill manifest. `sync-skills.py --scope
|
|
89
|
+
project` resolves that manifest into project-local CLI dirs (for example
|
|
90
|
+
`./.codex/skills`, `./.hermes/skills`, `./.kimi-code/skills`) and honors
|
|
91
|
+
`inherit_global: true` so a dev's global `~/.agents/skills.json` loadout is
|
|
92
|
+
merged in automatically.
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
| CLI | target dir | scope |
|
|
96
|
-
|---|---|---|
|
|
97
|
-
| Codex | `~/.codex/skills` | **global** — link ours in, never clobber foreign entries, removed on `leave` |
|
|
98
|
-
| Kimi | `./.kimi-code/skills` | **local** — a project-scoped mirror we fully manage (stale real copies replaced with symlinks) |
|
|
99
|
-
|
|
100
|
-
Add a CLI = one `dir|scope` line. Per-dev control via `.agents/local.json`
|
|
101
|
-
`skills`:
|
|
102
|
-
|
|
103
|
-
- `disabled: [...]` — never link these; pruned from managed mirrors.
|
|
104
|
-
- `defer_to_global: true` — **only if you run a global `~/.agents/skills` system.**
|
|
105
|
-
Skips any project skill whose name also exists there, so your global copy wins
|
|
106
|
-
and you get **zero duplicates** (it even yields the slot in `~/.codex/skills`).
|
|
107
|
-
Teammates with no global layer leave it `false` (default) and **inherit the full
|
|
108
|
-
set**. Override the global dir with `AGENTS_GLOBAL_SKILLS_DIR`.
|
|
109
|
-
|
|
110
|
-
Tasks: `mise run skills-relink` (re-fan), `mise run link-project-skills-to-clis`,
|
|
111
|
-
`mise run unlink-project-skills-from-clis`.
|
|
94
|
+
- Project-local skills with the same name shadow the global ones.
|
|
95
|
+
- No `defer_to_global` flag or bash cleanup scripts are needed anymore.
|
|
96
|
+
- The manifest is the only hand-edited skill SSOT; run `mise run skills-sync`
|
|
97
|
+
after changing it, or just re-enter the repo.
|
|
112
98
|
|
|
113
99
|
## Hindsight credentials — `mise run hindsight-setup`
|
|
114
100
|
|
|
@@ -137,6 +123,7 @@ Without a key the hooks **no-op gracefully** — recall/retain just do nothing.
|
|
|
137
123
|
```
|
|
138
124
|
.agents/
|
|
139
125
|
local.example.json # per-dev override template (copy -> local.json, gitignored)
|
|
126
|
+
skills.json # project skill manifest (SSOT for sync-skills.py)
|
|
140
127
|
hooks/
|
|
141
128
|
hooks.master.json # SSOT — the only hand-edited config
|
|
142
129
|
sync.py # fan-out engine (--install / --uninstall / --check)
|
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
# Source this, then call:
|
|
5
5
|
# hook_disabled <hook-id> # true if .hooks.disabled[] contains the id
|
|
6
6
|
# agent_disabled <agent> # true if .hooks.disabled_agents[] contains the agent
|
|
7
|
-
# skill_disabled <skill-name> # true if .skills.disabled[] contains the name
|
|
8
7
|
#
|
|
9
8
|
# All FAIL OPEN (return 1 = "not disabled") when `.agents/local.json` or `jq` is
|
|
10
|
-
# absent, so a missing/garbled local config can never silently kill hooks
|
|
9
|
+
# absent, so a missing/garbled local config can never silently kill hooks.
|
|
11
10
|
#
|
|
12
11
|
# `.agents/local.json` is gitignored — each dev owns their own. See
|
|
13
12
|
# `.agents/local.example.json` for the schema.
|
|
@@ -30,22 +29,13 @@ _caf_listed() {
|
|
|
30
29
|
|
|
31
30
|
hook_disabled() { _caf_listed '.hooks.disabled' "$1"; }
|
|
32
31
|
agent_disabled() { _caf_listed '.hooks.disabled_agents' "$1"; }
|
|
33
|
-
skill_disabled() { _caf_listed '.skills.disabled' "$1"; }
|
|
34
32
|
|
|
35
|
-
# True if the dev opted to let their GLOBAL agent system (~/.agents/
|
|
36
|
-
#
|
|
37
|
-
# Teammates with no global layer omit this and inherit the full project set.
|
|
33
|
+
# True if the dev opted to let their GLOBAL agent system (~/.agents/hooks) provide
|
|
34
|
+
# the hook layer, so project-scoped per-user injections should be suppressed.
|
|
38
35
|
skills_defer_to_global() {
|
|
39
36
|
local f
|
|
40
37
|
f="$(_caf_local_json)" || return 1
|
|
41
38
|
[[ -f "$f" ]] || return 1
|
|
42
39
|
command -v jq >/dev/null 2>&1 || return 1
|
|
43
|
-
jq -e '.
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
# True if <skill-name> is provided by the global agent SSOT. `-e` follows the
|
|
47
|
-
# ~/.agents/skills symlink (-> skillex/skill-sets/global) and its entries.
|
|
48
|
-
skill_is_global() {
|
|
49
|
-
local name="$1" gdir="${AGENTS_GLOBAL_SKILLS_DIR:-$HOME/.agents/skills}"
|
|
50
|
-
[[ -e "${gdir}/${name}" ]]
|
|
40
|
+
jq -e '.hooks.defer_to_global == true' "$f" >/dev/null 2>&1
|
|
51
41
|
}
|
|
@@ -72,10 +72,10 @@ def load_local() -> dict:
|
|
|
72
72
|
(so even Claude's committed hooks honor them); this only needs disabled
|
|
73
73
|
AGENTS, which gate install. CAF_HOOKS_SKIP_CODEX=1 is an env shortcut.
|
|
74
74
|
|
|
75
|
-
`defer_to_global`
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
`hooks.defer_to_global` means "I already run these hooks from a global agent
|
|
76
|
+
system" — so the shared per-user injections (codex/kimi/hermes) are
|
|
77
|
+
suppressed and actively removed. Claude's committed repo settings are
|
|
78
|
+
harmless and left in place.
|
|
79
79
|
"""
|
|
80
80
|
disabled_agents: set[str] = set()
|
|
81
81
|
defer_to_global = False
|
|
@@ -84,9 +84,8 @@ def load_local() -> dict:
|
|
|
84
84
|
try:
|
|
85
85
|
data = json.loads(p.read_text() or "{}")
|
|
86
86
|
hooks_cfg = data.get("hooks") or {}
|
|
87
|
-
skills_cfg = data.get("skills") or {}
|
|
88
87
|
disabled_agents = set(hooks_cfg.get("disabled_agents") or [])
|
|
89
|
-
defer_to_global = bool(hooks_cfg.get("defer_to_global"))
|
|
88
|
+
defer_to_global = bool(hooks_cfg.get("defer_to_global"))
|
|
90
89
|
except (json.JSONDecodeError, OSError) as exc:
|
|
91
90
|
warn(f"ignoring malformed .agents/local.json: {exc}")
|
|
92
91
|
if os.environ.get("CAF_HOOKS_SKIP_CODEX") == "1":
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$comment": "PER-DEV LOCAL OVERRIDES — copy this file to .agents/local.json (gitignored) and edit. Lets you opt out of individual hooks
|
|
2
|
+
"$comment": "PER-DEV LOCAL OVERRIDES — copy this file to .agents/local.json (gitignored) and edit. Lets you opt out of individual hooks or whole injected agents without touching committed config. Hooks self-skip at RUNTIME via .agents/hooks/lib/hook-guard.sh (so even Claude's committed hooks honor it); codex/hermes injections additionally skip at INSTALL time. Re-run `mise run hooks-sync` (or re-cd into the repo) after editing.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"$disabled_help": "Hook ids from .agents/hooks/hooks.master.json: skill-check-reminder, hindsight-recall, hindsight-retain, hindsight-session-end. Listed ids are skipped at runtime across ALL agents.",
|
|
5
5
|
"disabled": [],
|
|
6
6
|
"$disabled_agents_help": "Agent keys: claude, codex, kimi, hermes. Listed agents are NOT installed (codex/kimi/hermes injections are skipped/removed). Claude's hooks are committed and can't be fully removed per-dev — disable them individually via `disabled` instead.",
|
|
7
7
|
"disabled_agents": [],
|
|
8
|
-
"$defer_to_global_help": "Set true if you already run these hooks from a GLOBAL agent system (~/.agents/hooks). When true, sync.py suppresses AND removes the shared per-user injections (codex/kimi/hermes) so a project never double-injects into ~/.codex / ~/.kimi-code; Claude's committed repo settings are left in place.
|
|
9
|
-
"defer_to_global": false
|
|
10
|
-
},
|
|
11
|
-
"skills": {
|
|
12
|
-
"$disabled_help": "Skill directory names under .agents/skills/. Listed skills are NOT symlinked into any agent CLI dir for you, and are pruned from your managed mirrors.",
|
|
13
|
-
"disabled": [],
|
|
14
|
-
"$defer_to_global_help": "Set true ONLY if you run a global agent system at ~/.agents/skills. When true, the linker skips any project skill whose name also exists in your global SSOT, so your global copy wins and you get ZERO duplicates/conflicts (and yields the slot in shared dirs like ~/.codex/skills). Teammates with no global layer leave this false (the default) and inherit the FULL project skill set. Override the global dir with the AGENTS_GLOBAL_SKILLS_DIR env var.",
|
|
8
|
+
"$defer_to_global_help": "Set true if you already run these hooks from a GLOBAL agent system (~/.agents/hooks). When true, sync.py suppresses AND removes the shared per-user injections (codex/kimi/hermes) so a project never double-injects into ~/.codex / ~/.kimi-code; Claude's committed repo settings are left in place. On a machine with a global install, pjangler skips scaffolding this whole layer, so you rarely need to set this by hand.",
|
|
15
9
|
"defer_to_global": false
|
|
16
10
|
}
|
|
17
11
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
{%
|
|
2
|
-
{% set
|
|
1
|
+
{% if ticket_provider == 'plane' and plane_project_id -%}
|
|
2
|
+
{% set board_url = plane_base ~ '/' ~ plane_workspace ~ '/projects/' ~ plane_project_id ~ '/issues/' -%}
|
|
3
|
+
{% else -%}
|
|
4
|
+
{% set board_url = '' -%}
|
|
5
|
+
{% endif -%}
|
|
3
6
|
{
|
|
4
7
|
"project_name": {{ project_name | tojson }},
|
|
5
8
|
"project_description": {{ project_description | tojson }},
|
|
@@ -7,17 +10,10 @@
|
|
|
7
10
|
"repo_path": "",
|
|
8
11
|
"ticket_provider": {
|
|
9
12
|
"type": {{ ticket_provider | tojson }},
|
|
10
|
-
"workspace": {{
|
|
13
|
+
"workspace": {{ plane_workspace | tojson }},
|
|
11
14
|
"identifier": {{ project_identifier | tojson }},
|
|
12
|
-
"board_id": {{
|
|
13
|
-
"
|
|
15
|
+
"board_id": {{ plane_project_id | tojson }},
|
|
16
|
+
"board_url": {{ board_url | tojson }}
|
|
14
17
|
},
|
|
15
|
-
"agents": {}
|
|
16
|
-
"automation": {
|
|
17
|
-
"reconcile": {
|
|
18
|
-
"enabled": false,
|
|
19
|
-
"grace_hours": 0,
|
|
20
|
-
"auto_review": true
|
|
21
|
-
}
|
|
22
|
-
}
|
|
18
|
+
"agents": {}
|
|
23
19
|
}
|
|
@@ -20,23 +20,24 @@ script = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-agentfiles.sh
|
|
|
20
20
|
[[hooks.enter]]
|
|
21
21
|
script = "op inject -i .env.op > .env"
|
|
22
22
|
[[hooks.enter]]
|
|
23
|
+
script = "sync-skills.py --scope project"
|
|
24
|
+
[[hooks.enter]]
|
|
23
25
|
script = "[ -f '{% raw %}{{config_root}}{% endraw %}/.mise/scripts/codegraph.sh' ] && '{% raw %}{{config_root}}{% endraw %}/.mise/scripts/codegraph.sh' || true"
|
|
24
26
|
{%- if agent_hooks_layer %}
|
|
25
27
|
[[hooks.enter]]
|
|
26
|
-
script = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-project-skills-to-clis.sh'"
|
|
27
|
-
[[hooks.enter]]
|
|
28
28
|
script = "'{% raw %}{{config_root}}{% endraw %}/.agents/hooks/sync.py' --install --quiet"
|
|
29
29
|
{%- endif %}
|
|
30
30
|
{%- if agent_hooks_layer %}
|
|
31
31
|
[[hooks.leave]]
|
|
32
|
-
script = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/unlink-project-skills-from-clis.sh'"
|
|
33
|
-
[[hooks.leave]]
|
|
34
32
|
script = "'{% raw %}{{config_root}}{% endraw %}/.agents/hooks/sync.py' --uninstall --quiet"
|
|
35
33
|
{%- endif %}
|
|
36
34
|
|
|
37
35
|
[[watch_files]]
|
|
38
36
|
patterns = ["AGENTS.md"]
|
|
39
37
|
task = "link-agentfiles"
|
|
38
|
+
[[watch_files]]
|
|
39
|
+
patterns = [".agents/skills.json"]
|
|
40
|
+
task = "skills-sync"
|
|
40
41
|
{% if agent_hooks_layer %}
|
|
41
42
|
# Re-fan-out the agent hooks whenever the single source of truth changes.
|
|
42
43
|
[[watch_files]]
|
|
@@ -46,6 +47,10 @@ task = "hooks-sync"
|
|
|
46
47
|
[tasks.link-agentfiles]
|
|
47
48
|
description = "Symlink all agent files to AGENTS.md"
|
|
48
49
|
run = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-agentfiles.sh'"
|
|
50
|
+
|
|
51
|
+
[tasks.skills-sync]
|
|
52
|
+
description = "Sync skills from manifest to local CLI dirs"
|
|
53
|
+
run = "sync-skills.py --scope project"
|
|
49
54
|
{% if agent_hooks_layer %}
|
|
50
55
|
# --- Project-scoped agent hooks + skill fan-out (see .agents/hooks/README.md) ---
|
|
51
56
|
|
|
@@ -60,18 +65,6 @@ run = "'{% raw %}{{config_root}}{% endraw %}/.agents/hooks/sync.py' --check"
|
|
|
60
65
|
[tasks.hooks-uninstall]
|
|
61
66
|
description = "Remove per-user agent-hook injections (codex/kimi/hermes)"
|
|
62
67
|
run = "'{% raw %}{{config_root}}{% endraw %}/.agents/hooks/sync.py' --uninstall"
|
|
63
|
-
|
|
64
|
-
[tasks.link-project-skills-to-clis]
|
|
65
|
-
description = "Fan .agents/skills out to each agent CLI; honors local.json defer_to_global + disabled"
|
|
66
|
-
run = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-project-skills-to-clis.sh'"
|
|
67
|
-
|
|
68
|
-
[tasks.unlink-project-skills-from-clis]
|
|
69
|
-
description = "Remove project skill symlinks from shared per-CLI dirs"
|
|
70
|
-
run = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/unlink-project-skills-from-clis.sh'"
|
|
71
|
-
|
|
72
|
-
[tasks.skills-relink]
|
|
73
|
-
description = "Re-fan the project skill set to all CLIs"
|
|
74
|
-
run = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-project-skills-to-clis.sh'"
|
|
75
68
|
{% endif %}
|
|
76
69
|
[tasks.hindsight-setup]
|
|
77
70
|
description = "Provision this dev's shared project Hindsight key from 1Password into .env (op inject)"
|
|
@@ -11,7 +11,7 @@ memory/state checkpointing.
|
|
|
11
11
|
| What it scaffolds | A new top-level project | An agent role inside an existing project |
|
|
12
12
|
| Copier target | `./my-new-project/` | `./agents/hermes/<role>/` |
|
|
13
13
|
| Asks | project name + description | role + purpose + tone |
|
|
14
|
-
| Post-gen artifacts |
|
|
14
|
+
| Post-gen artifacts | Plane project, bmad init, mise tasks | Plane project, Telegram bot wiring, agent-hm-* runtime repo, systemd units |
|
|
15
15
|
|
|
16
16
|
CommonProject runs first to create the umbrella project. hermes-agent-template
|
|
17
17
|
runs second (for each agent role you want) to drop agents into it.
|
|
@@ -20,8 +20,8 @@ runs second (for each agent role you want) to drop agents into it.
|
|
|
20
20
|
|
|
21
21
|
The template provisions a single Hermes role per invocation. The `pm` role
|
|
22
22
|
handles project management and triage, and also runs the continuous ticket
|
|
23
|
-
sentinel out-of-band: a provider-agnostic board-reconciliation pass (
|
|
24
|
-
Trello) with an autonomous adversarial review (act, do not wait). The
|
|
23
|
+
sentinel out-of-band: a provider-agnostic board-reconciliation pass (Linear,
|
|
24
|
+
Plane, or Trello) with an autonomous adversarial review (act, do not wait). The
|
|
25
25
|
sentinel runs as the PM's **heartbeat** — a fused systemd timer tick that does
|
|
26
26
|
the reconciliation pass and then a gated runtime checkpoint. (There is no
|
|
27
27
|
separate `scrum-master` role; its duties folded into the PM heartbeat.)
|
|
@@ -47,7 +47,7 @@ The template will:
|
|
|
47
47
|
5. Populate it with the runtime scaffold (config.yaml, SOUL.md, memories, consumer.py)
|
|
48
48
|
6. Add it as a git submodule at `agents/hermes/pm/runtime/` (== HERMES_HOME)
|
|
49
49
|
7. Prompt for a BotFather token, store it in `runtime/.env`
|
|
50
|
-
8. Create
|
|
50
|
+
8. Create a Plane project in your configured workspace
|
|
51
51
|
9. Install systemd `--user` units: gateway, consumer, heartbeat timer (reconcile + checkpoint)
|
|
52
52
|
10. Append the agent to `~/.hermes/agents-registry.yaml`
|
|
53
53
|
|
|
@@ -68,7 +68,7 @@ you to review it. Keys:
|
|
|
68
68
|
| `fleet` | `fleet_env`, `registry_file` | Fleet source-of-truth + registry locations |
|
|
69
69
|
| `fleet` | `oauth_file`, `codex_home` | Shared Hermes OAuth store + Codex CLI/app-server auth home |
|
|
70
70
|
| `fleet` | `runtime_scaffold_dir` | Fallback scaffold (if agent-local one is missing) |
|
|
71
|
-
| `fleet` | `canonical_skills_dir`, `
|
|
71
|
+
| `fleet` | `canonical_skills_dir`, `symlinked_runtime_skills` | Skills mirrored into each profile |
|
|
72
72
|
| `github` | `runtime_repo_owner` | Owner of the `agent-hm-*` runtime repos |
|
|
73
73
|
| `plane` | `base`, `workspace` | Plane URL + workspace slug |
|
|
74
74
|
| `bloodbank` | `nats_host`, `nats_port`, `compose_dir` | NATS endpoint + compose dir hint |
|
|
@@ -138,14 +138,14 @@ to force re-run:
|
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
140
|
cd agents/hermes/pm
|
|
141
|
-
rm .scripts/.done-
|
|
142
|
-
SKIP_SYSTEMD=1 ./.scripts/
|
|
141
|
+
rm .scripts/.done-40-plane
|
|
142
|
+
SKIP_TELEGRAM=1 SKIP_SYSTEMD=1 ./.scripts/40-plane.sh
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
## Retiring an agent
|
|
146
146
|
|
|
147
147
|
(TODO: ship `retire.sh` in v1.1)
|
|
148
148
|
|
|
149
|
-
Manual: stop systemd units, `hermes profile delete`, archive the
|
|
150
|
-
|
|
149
|
+
Manual: stop systemd units, `hermes profile delete`, archive the Plane
|
|
150
|
+
project, `/deletebot` in BotFather, archive the
|
|
151
151
|
`agent-hm-*` runtime repo, remove the registry entry.
|
|
@@ -1,66 +1 @@
|
|
|
1
|
-
|
|
2
|
-
#
|
|
3
|
-
# This file holds every environment-specific default the provisioning scripts
|
|
4
|
-
# need. Copy it to ~/.config/hermes-agent-template/config.toml (the first
|
|
5
|
-
# provisioning run does this for you) and edit the values for YOUR machine.
|
|
6
|
-
#
|
|
7
|
-
# Resolution precedence for each value (highest wins):
|
|
8
|
-
# explicit env var > ~/.hermes/fleet.env > this file > built-in fallback
|
|
9
|
-
#
|
|
10
|
-
# Override the config location with $HERMES_TEMPLATE_CONFIG if you keep it
|
|
11
|
-
# somewhere other than $XDG_CONFIG_HOME/hermes-agent-template/config.toml.
|
|
12
|
-
|
|
13
|
-
[fleet]
|
|
14
|
-
# Absolute path to the shared Hermes executable every agent launcher execs.
|
|
15
|
-
hermes_bin = "~/.hermes/hermes-agent/.venv/bin/hermes"
|
|
16
|
-
# Checkout of the hermes-agent repo. Its .venv is used to install nats-py, etc.
|
|
17
|
-
hermes_repo = "~/.hermes/hermes-agent"
|
|
18
|
-
# Fallback runtime scaffold dir — used only when an agent's vendored
|
|
19
|
-
# ./.runtime-scaffold is missing.
|
|
20
|
-
runtime_scaffold_dir = "~/code/hermes-agent-template/runtime-scaffold"
|
|
21
|
-
# Shared fleet source-of-truth env file + fleet registry. ~ is expanded.
|
|
22
|
-
fleet_env = "~/.hermes/fleet.env"
|
|
23
|
-
registry_file = "~/.hermes/agents-registry.yaml"
|
|
24
|
-
# Shared auth roots. HERMES_OAUTH_FILE is the Hermes provider OAuth store
|
|
25
|
-
# (including openai-codex); CODEX_HOME is for Codex CLI/app-server auth.
|
|
26
|
-
oauth_file = "~/.hermes/auth.json"
|
|
27
|
-
codex_home = "~/.codex"
|
|
28
|
-
# Canonical external skills dir mirrored into each agent profile.
|
|
29
|
-
canonical_skills_dir = "/home/delorenj/.agents/skills"
|
|
30
|
-
# PM-only external skill libraries surfaced alongside Hermes built-ins.
|
|
31
|
-
pm_external_skill_dirs = [
|
|
32
|
-
"~/code/skillex/skill-sets/global/.system",
|
|
33
|
-
"~/code/skillex/packs/bmad/6.10.2",
|
|
34
|
-
]
|
|
35
|
-
# Voxxy plugin + service defaults for Hermes PM agents.
|
|
36
|
-
voxxy_plugin_dir = "~/code/voxxy/plugins/tts/voxxy"
|
|
37
|
-
vox_url = "https://vox.delo.sh"
|
|
38
|
-
# Canonical PM config.yaml the provisioner seeds each runtime's config.yaml from.
|
|
39
|
-
# This is the fleet-wide Hermes inference/skill config (model, toolsets, etc.)
|
|
40
|
-
# every agent runtime starts from. ~ is expanded.
|
|
41
|
-
# canonical_pm_config = "~/.hermes/config.yaml"
|
|
42
|
-
# Skills symlinked into every agent's runtime skills root.
|
|
43
|
-
symlinked_runtime_skills = [
|
|
44
|
-
"delonet-conventions",
|
|
45
|
-
"delonet-dotenv",
|
|
46
|
-
"hermes-pm-template-maintenance",
|
|
47
|
-
"hindsight",
|
|
48
|
-
"33god-projects",
|
|
49
|
-
"subagent-driven-development",
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
[github]
|
|
53
|
-
# Owner of the per-agent runtime repos (creates <owner>/agent-hm-<repo>-<role>).
|
|
54
|
-
runtime_repo_owner = "delorenj"
|
|
55
|
-
|
|
56
|
-
[plane]
|
|
57
|
-
# Plane instance base URL and workspace slug (one project per agent).
|
|
58
|
-
base = "https://plane.delo.sh"
|
|
59
|
-
workspace = "33god"
|
|
60
|
-
|
|
61
|
-
[bloodbank]
|
|
62
|
-
# NATS endpoint the consumer connects to.
|
|
63
|
-
nats_host = "127.0.0.1"
|
|
64
|
-
nats_port = 4222
|
|
65
|
-
# Where the bloodbank docker compose lives (used only for a hint message). ~ ok.
|
|
66
|
-
compose_dir = "~/code/33GOD/bloodbank"
|
|
1
|
+
template/.scripts/config.example.toml
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
# 1. Renders agents/hermes/<role>/{role.yaml, SOUL.md, hermes, .scripts/}
|
|
13
13
|
# 2. Creates a per-agent runtime repo gh:delorenj/agent-hm-<repo>-<role>
|
|
14
14
|
# 3. Submodules it at agents/hermes/<role>/runtime/ (this is HERMES_HOME)
|
|
15
|
-
# 4. Creates
|
|
15
|
+
# 4. Creates a Plane project in 33god workspace
|
|
16
16
|
# 6. Prompts for a BotFather Telegram token, stores in runtime/.env
|
|
17
17
|
# 7. Installs a Bloodbank consumer + heartbeat timer (reconcile + checkpoint)
|
|
18
18
|
# 8. Appends to ~/.hermes/agents-registry.yaml
|
|
19
19
|
#
|
|
20
|
-
# Environment-specific defaults (Hermes binary path, runtime repo owner,
|
|
21
|
-
#
|
|
20
|
+
# Environment-specific defaults (Hermes binary path, runtime repo owner, Plane
|
|
21
|
+
# workspace/URL, NATS endpoint, skills dir, …) are NOT hardcoded — they live in
|
|
22
22
|
# ~/.config/hermes-agent-template/config.toml, seeded from config.example.toml on
|
|
23
23
|
# first run. Edit that file to retarget the template for a different machine/user.
|
|
24
24
|
|
|
@@ -59,6 +59,7 @@ ticket_provider:
|
|
|
59
59
|
help: "Ticket system this agent's board lives in"
|
|
60
60
|
default: plane
|
|
61
61
|
choices:
|
|
62
|
+
"Linear": linear
|
|
62
63
|
"Plane": plane
|
|
63
64
|
"Trello": trello
|
|
64
65
|
|