@delorenj/pjangler 1.2.4 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delorenj/pjangler",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "Project subsystem bootstrapper CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -79,8 +79,41 @@ primary_language:
79
79
  default: python
80
80
  when: false
81
81
 
82
- # --- Post-generation tasks ---
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
- disabled_agents = set((data.get("hooks") or {}).get("disabled_agents") or [])
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, and route work to other agents in the fleet (e.g. the dev role
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 kanban-orchestrated codex mode
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: