@delorenj/pjangler 1.2.3 → 1.2.6
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 +1950 -2018
- package/dist/mcp-server.js +668 -739
- package/package.json +1 -1
- package/templates/commonproject/copier.yml +34 -2
- package/templates/commonproject/template/.agents/hooks/sync.py +12 -1
- package/templates/commonproject/template/.agents/local.example.json +3 -1
- package/templates/commonproject/template/mise.toml.jinja +8 -4
- package/templates/hermes-agent/template/.scripts/70-systemd.sh +1 -0
- package/templates/hermes-agent/template/.scripts/sentinel.prompt.md.jinja +7 -0
- package/templates/hermes-agent/template/SOUL.md.jinja +7 -2
package/package.json
CHANGED
|
@@ -79,8 +79,41 @@ primary_language:
|
|
|
79
79
|
default: python
|
|
80
80
|
when: false
|
|
81
81
|
|
|
82
|
-
#
|
|
82
|
+
# Whether to scaffold the project-scoped agent-hooks + skill fan-out layer
|
|
83
|
+
# (.agents/hooks + the mise enter/leave wiring that injects into each agent CLI's
|
|
84
|
+
# per-user config). Defaults true so a bare `copier copy` still gets it. pjangler
|
|
85
|
+
# passes `--data agent_hooks_layer=false` when the machine already runs a GLOBAL
|
|
86
|
+
# agent-hooks install (~/.agents/hooks) — so a fresh project never re-injects the
|
|
87
|
+
# same hooks into shared per-user configs like ~/.codex or ~/.kimi-code.
|
|
88
|
+
agent_hooks_layer:
|
|
89
|
+
type: bool
|
|
90
|
+
default: true
|
|
91
|
+
when: false
|
|
92
|
+
|
|
93
|
+
# When agent_hooks_layer is false, omit the project-scoped hook tree + skill-link
|
|
94
|
+
# scripts entirely (the mise.toml wiring is already gated inside the template).
|
|
95
|
+
# The `.copier-noop-never-matches` sentinel keeps every pattern non-empty when the
|
|
96
|
+
# layer is enabled, which copier requires.
|
|
97
|
+
_exclude:
|
|
98
|
+
- "copier.yml"
|
|
99
|
+
- "~*"
|
|
100
|
+
- "*.py[co]"
|
|
101
|
+
- "__pycache__"
|
|
102
|
+
- ".git"
|
|
103
|
+
- ".DS_Store"
|
|
104
|
+
- ".svn"
|
|
105
|
+
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/hooks{% endif %}"
|
|
106
|
+
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/hooks/**{% endif %}"
|
|
107
|
+
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/local.example.json{% endif %}"
|
|
108
|
+
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.mise/scripts/link-project-skills-to-clis.sh{% endif %}"
|
|
109
|
+
- "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.mise/scripts/unlink-project-skills-from-clis.sh{% endif %}"
|
|
83
110
|
|
|
111
|
+
# --- Post-generation tasks ---
|
|
112
|
+
#
|
|
113
|
+
# NOTE: intentionally does NOT run `mise trust`. Trusting the repo fires the mise
|
|
114
|
+
# `[hooks].enter` array, which (when the agent-hooks layer is present) injects
|
|
115
|
+
# into the caller's shared per-user CLI configs. Scaffolding must never mutate
|
|
116
|
+
# global state as a side effect — the operator trusts/enters the repo themselves.
|
|
84
117
|
_tasks:
|
|
85
118
|
- "cp ~/.config/git/ignore .gitignore 2>/dev/null || echo '# Add ignores here' > .gitignore"
|
|
86
119
|
# Ensure secrets + per-dev agent-hook/skill overrides are ignored (appended after the base ignore).
|
|
@@ -89,4 +122,3 @@ _tasks:
|
|
|
89
122
|
- "ln -sf AGENTS.md GEMINI.md"
|
|
90
123
|
# Stamp the repo's absolute path into .project.json (the SOT) post-render.
|
|
91
124
|
- "python3 -c \"import json,os,pathlib; p=pathlib.Path('.project.json'); d=json.loads(p.read_text()); d['repo_path']=os.getcwd(); p.write_text(json.dumps(d,indent=2)+chr(10))\""
|
|
92
|
-
- "mise trust"
|
|
@@ -71,17 +71,28 @@ def load_local() -> dict:
|
|
|
71
71
|
Note: individual disabled HOOKS are enforced at RUNTIME by lib/hook-guard.sh
|
|
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
|
+
|
|
75
|
+
`defer_to_global` (under either `hooks` or `skills`) means "I already run
|
|
76
|
+
these hooks from a global agent system" — so the shared per-user injections
|
|
77
|
+
(codex/kimi/hermes) are suppressed and actively removed. Claude's committed
|
|
78
|
+
repo settings are harmless and left in place.
|
|
74
79
|
"""
|
|
75
80
|
disabled_agents: set[str] = set()
|
|
81
|
+
defer_to_global = False
|
|
76
82
|
p = REPO_ROOT / ".agents" / "local.json"
|
|
77
83
|
if p.exists():
|
|
78
84
|
try:
|
|
79
85
|
data = json.loads(p.read_text() or "{}")
|
|
80
|
-
|
|
86
|
+
hooks_cfg = data.get("hooks") or {}
|
|
87
|
+
skills_cfg = data.get("skills") or {}
|
|
88
|
+
disabled_agents = set(hooks_cfg.get("disabled_agents") or [])
|
|
89
|
+
defer_to_global = bool(hooks_cfg.get("defer_to_global")) or bool(skills_cfg.get("defer_to_global"))
|
|
81
90
|
except (json.JSONDecodeError, OSError) as exc:
|
|
82
91
|
warn(f"ignoring malformed .agents/local.json: {exc}")
|
|
83
92
|
if os.environ.get("CAF_HOOKS_SKIP_CODEX") == "1":
|
|
84
93
|
disabled_agents.add("codex")
|
|
94
|
+
if defer_to_global:
|
|
95
|
+
disabled_agents.update({"codex", "kimi", "hermes"})
|
|
85
96
|
return {"disabled_agents": disabled_agents}
|
|
86
97
|
|
|
87
98
|
|
|
@@ -4,7 +4,9 @@
|
|
|
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
|
-
"disabled_agents": []
|
|
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. Implied by skills.defer_to_global. On a machine with a global install, pjangler skips scaffolding this whole layer, so you rarely need to set this by hand.",
|
|
9
|
+
"defer_to_global": false
|
|
8
10
|
},
|
|
9
11
|
"skills": {
|
|
10
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.",
|
|
@@ -16,27 +16,31 @@ enter = [
|
|
|
16
16
|
"{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-agentfiles.sh",
|
|
17
17
|
"op inject -i .env.op > .env",
|
|
18
18
|
"{% raw %}{{config_root}}{% endraw %}/.mise/scripts/codegraph.sh",
|
|
19
|
+
{%- if agent_hooks_layer %}
|
|
19
20
|
"{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-project-skills-to-clis.sh",
|
|
20
21
|
"{% raw %}{{config_root}}{% endraw %}/.agents/hooks/sync.py --install --quiet",
|
|
22
|
+
{%- endif %}
|
|
21
23
|
]
|
|
24
|
+
{%- if agent_hooks_layer %}
|
|
22
25
|
leave = [
|
|
23
26
|
"{% raw %}{{config_root}}{% endraw %}/.mise/scripts/unlink-project-skills-from-clis.sh",
|
|
24
27
|
"{% raw %}{{config_root}}{% endraw %}/.agents/hooks/sync.py --uninstall --quiet",
|
|
25
28
|
]
|
|
29
|
+
{%- endif %}
|
|
26
30
|
|
|
27
31
|
[[watch_files]]
|
|
28
32
|
patterns = ["AGENTS.md"]
|
|
29
33
|
task = "link-agentfiles"
|
|
30
|
-
|
|
34
|
+
{% if agent_hooks_layer %}
|
|
31
35
|
# Re-fan-out the agent hooks whenever the single source of truth changes.
|
|
32
36
|
[[watch_files]]
|
|
33
37
|
patterns = [".agents/hooks/hooks.master.json"]
|
|
34
38
|
task = "hooks-sync"
|
|
35
|
-
|
|
39
|
+
{% endif %}
|
|
36
40
|
[tasks.link-agentfiles]
|
|
37
41
|
description = "Symlink all agent files to AGENTS.md"
|
|
38
42
|
run = "{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-agentfiles.sh"
|
|
39
|
-
|
|
43
|
+
{% if agent_hooks_layer %}
|
|
40
44
|
# --- Project-scoped agent hooks + skill fan-out (see .agents/hooks/README.md) ---
|
|
41
45
|
|
|
42
46
|
[tasks.hooks-sync]
|
|
@@ -62,7 +66,7 @@ run = "{% raw %}{{config_root}}{% endraw %}/.mise/scripts/unlink-project-skills-
|
|
|
62
66
|
[tasks.skills-relink]
|
|
63
67
|
description = "Re-fan the project skill set to all CLIs"
|
|
64
68
|
run = "{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-project-skills-to-clis.sh"
|
|
65
|
-
|
|
69
|
+
{% endif %}
|
|
66
70
|
[tasks.hindsight-setup]
|
|
67
71
|
description = "Provision this dev's shared project Hindsight key from 1Password into .env (op inject)"
|
|
68
72
|
run = "{% raw %}{{config_root}}{% endraw %}/.mise/scripts/hindsight-setup.sh"
|
|
@@ -32,6 +32,7 @@ Type=simple
|
|
|
32
32
|
Environment=HERMES_HOME=$RUNTIME
|
|
33
33
|
Environment=HERMES_OAUTH_FILE=$HERMES_OAUTH_FILE
|
|
34
34
|
Environment=CODEX_HOME=$CODEX_HOME
|
|
35
|
+
Environment=HERMES_KANBAN_DISPATCH_IN_GATEWAY=0
|
|
35
36
|
EnvironmentFile=-$RUNTIME/.env
|
|
36
37
|
ExecStart=$HERMES_BIN gateway run --replace
|
|
37
38
|
Restart=on-failure
|
|
@@ -6,6 +6,13 @@ A cheap systemd heartbeat already decided this full pass is needed.
|
|
|
6
6
|
Working repo: the git root containing this role at `agents/hermes/{{ role }}/`.
|
|
7
7
|
Ticket provider: **{{ ticket_provider }}** (reached only through the adapter — see below).
|
|
8
8
|
|
|
9
|
+
{% if ticket_provider == "plane" -%}
|
|
10
|
+
**Plane is the authoritative repo ticket board/SOT for this PM.** Hermes local
|
|
11
|
+
Kanban must NOT be an active durable task lifecycle surface. Local Kanban may
|
|
12
|
+
only run as an explicitly configured ephemeral child execution queue and must
|
|
13
|
+
never close/move authoritative repo tickets.
|
|
14
|
+
|
|
15
|
+
{% endif -%}
|
|
9
16
|
You are the **{{ target_repo }} PM**, running your continuous board-reconciliation
|
|
10
17
|
pass. Act autonomously, but stay inside the project contracts. Read
|
|
11
18
|
`agents/hermes/{{ role }}/SOUL.md` and the engine docs under
|
|
@@ -55,12 +55,17 @@ read it before publishing a type you haven't published before.
|
|
|
55
55
|
{% if role == "pm" -%}
|
|
56
56
|
You are the **project manager**. You triage incoming requests from Telegram /
|
|
57
57
|
Bloodbank command lanes, decompose them into discrete tasks on the
|
|
58
|
-
Plane board
|
|
58
|
+
**Plane board only**, and route work to other agents in the fleet (e.g. the dev role
|
|
59
59
|
on `bloodbank.cmd.v1.agent.{{ target_repo }}-dev.task.assign`). You do not
|
|
60
60
|
write application code. You do not approve merges.
|
|
61
61
|
|
|
62
|
+
**Plane is the authoritative repo ticket board/SOT for this PM.** Hermes local
|
|
63
|
+
Kanban must NOT be an active durable task lifecycle surface. The kanban toolset
|
|
64
|
+
is removed from the PM's cli surface. Local Kanban may only run as an explicitly-configured
|
|
65
|
+
ephemeral child execution queue and must never close/move authoritative repo tickets.
|
|
66
|
+
|
|
62
67
|
Default execution workflow for implementation delivery: use
|
|
63
|
-
`subagent-driven-development` in
|
|
68
|
+
`subagent-driven-development` in Plane-ticket-orchestrated implementation mode
|
|
64
69
|
(WIP=1, spec review gate, quality review gate).
|
|
65
70
|
|
|
66
71
|
Decision events you commonly emit:
|